home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / unix / rcs.07 < prev    next >
Internet Message Format  |  1989-11-19  |  86KB

  1. Path: xanth!ames!apple!sun-barr!newstop!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i222:  rcs - revision control system, Part07/14
  5. Message-ID: <128098@sun.Eng.Sun.COM>
  6. Date: 19 Nov 89 09:25:07 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 2809
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: rsbx@cbmvax.commodore.com (Raymond S. Brand)
  12. Posting-number: Volume 89, Issue 222
  13. Archive-name: unix/rcs.07
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    rcs/rcs.rcsfiles/partime.c,v
  24. #    rcs/rcs.rcsfiles/rcs.c,v
  25. # This is archive 7 of a 14-part kit.
  26. # This archive created: Sun Nov 19 01:12:08 1989
  27. if `test ! -d rcs`
  28. then
  29.   mkdir rcs
  30.   echo "mkdir rcs"
  31. fi
  32. if `test ! -d rcs/rcs.rcsfiles`
  33. then
  34.   mkdir rcs/rcs.rcsfiles
  35.   echo "mkdir rcs/rcs.rcsfiles"
  36. fi
  37. echo "extracting rcs/rcs.rcsfiles/partime.c,v"
  38. sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/partime.c,v
  39. Xhead     1.4;
  40. Xbranch   1.4.2;
  41. Xaccess   ;
  42. Xsymbols  amiga_rcs:1.4.2 cbmvax_source:1.4.1 uunet_june89_dist:1.4;
  43. Xlocks    ; strict;
  44. Xcomment  @ * @;
  45. X
  46. X
  47. X1.4
  48. Xdate     89.05.01.14.48.46;  author narten;  state Exp;
  49. Xbranches 1.4.1.1 1.4.2.1;
  50. Xnext     ;
  51. X
  52. X1.4.1.1
  53. Xdate     89.08.11.01.41.57;  author rsbx;  state Exp;
  54. Xbranches ;
  55. Xnext     ;
  56. X
  57. X1.4.2.1
  58. Xdate     89.10.13.19.17.41;  author rsbx;  state Exp;
  59. Xbranches ;
  60. Xnext     1.4.2.2;
  61. X
  62. X1.4.2.2
  63. Xdate     89.10.15.15.43.31;  author rsbx;  state Exp;
  64. Xbranches ;
  65. Xnext     1.4.2.3;
  66. X
  67. X1.4.2.3
  68. Xdate     89.10.29.14.47.46;  author rsbx;  state Exp;
  69. Xbranches ;
  70. Xnext     ;
  71. X
  72. X
  73. Xdesc
  74. X@Parse date/time string into a TM structure.
  75. X@
  76. X
  77. X
  78. X
  79. X1.4
  80. Xlog
  81. X@checked in with -k by rsbx at 89.08.10.16.06.05.
  82. X@
  83. Xtext
  84. X@/*
  85. X * PARTIME        parse date/time string into a TM structure
  86. X *
  87. X * Usage:
  88. X *      #include "time.h"             -- expanded tm structure
  89. X *    char *str; struct tm *tp;
  90. X *    partime(str,tp);
  91. X * Returns:
  92. X *    0 if parsing failed
  93. X *    else time values in specified TM structure (unspecified values
  94. X *        set to TMNULL)
  95. X * Notes:
  96. X *    This code is quasi-public; it may be used freely in like software.
  97. X *    It is not to be sold, nor used in licensed software without
  98. X *    permission of the author.
  99. X *    For everyone's benefit, please report bugs and improvements!
  100. X *     Copyright 1980 by Ken Harrenstien, SRI International.
  101. X *    (ARPANET: KLH @@ SRI)
  102. X */
  103. X
  104. X/* Hacknotes:
  105. X *    If parsing changed so that no backup needed, could perhaps modify
  106. X *        to use a FILE input stream.  Need terminator, though.
  107. X *    Perhaps should return 0 on success, else a non-zero error val?
  108. X *    Flush AMPM from TM structure and handle locally within PARTIME,
  109. X *        like midnight/noon?
  110. X */
  111. X
  112. X#ifndef lint
  113. Xstatic char rcsid[]=
  114. X"$Header: /usr/src/local/bin/rcs/src/RCS/partime.c,v 1.4 89/05/01 14:48:46 narten Exp $";
  115. X#endif
  116. X
  117. X/* $Log:    partime.c,v $
  118. X * Revision 1.4  89/05/01  14:48:46  narten
  119. X * fixed #ifdef DEBUG construct
  120. X * 
  121. X * Revision 1.3  88/11/08  12:02:15  narten
  122. X * changes from  eggert@@sm.unisys.com (Paul Eggert)
  123. X * 
  124. X * Revision 1.3  88/08/28  14:53:40  eggert
  125. X * Remove unportable "#endif XXX"s.
  126. X * 
  127. X * Revision 1.2  87/03/27  14:21:53  jenkins
  128. X * Port to suns
  129. X * 
  130. X * Revision 1.1  84/01/23  14:50:07  kcs
  131. X * Initial revision
  132. X * 
  133. X * Revision 1.1  82/05/06  11:38:26  wft
  134. X * Initial revision
  135. X * 
  136. X */
  137. X
  138. X#include <stdio.h>
  139. X#include <ctype.h>
  140. X#include "time.h"
  141. X
  142. X#ifndef lint
  143. Xstatic char timeid[] = TIMEID;
  144. X#endif
  145. X
  146. Xstruct tmwent {
  147. X    char *went;
  148. X    long wval;    /* must be big enough to hold pointer or integer */
  149. X    char wflgs;
  150. X    char wtype;
  151. X};
  152. X    /* wflgs */
  153. X#define TWSPEC 01    /* Word wants special processing */
  154. X#define TWTIME 02    /* Word is a time value (absence implies date) */
  155. X#define TWDST  04    /* Word is a DST-type timezone */
  156. X#define TW1200 010    /* Word is NOON or MIDNIGHT (sigh) */
  157. X
  158. Xint pt12hack();
  159. Xint ptnoise();
  160. Xstruct tmwent tmwords [] = {
  161. X    {"january",      0, 0, TM_MON},
  162. X    {"february",     1, 0, TM_MON},
  163. X    {"march",        2, 0, TM_MON},
  164. X    {"april",        3, 0, TM_MON},
  165. X    {"may",          4, 0, TM_MON},
  166. X    {"june",         5, 0, TM_MON},
  167. X    {"july",         6, 0, TM_MON},
  168. X    {"august",       7, 0, TM_MON},
  169. X    {"september",    8, 0, TM_MON},
  170. X    {"october",      9, 0, TM_MON},
  171. X    {"november",     10, 0, TM_MON},
  172. X    {"december",     11, 0, TM_MON},
  173. X
  174. X    {"sunday",       0, 0, TM_WDAY},
  175. X    {"monday",       1, 0, TM_WDAY},
  176. X    {"tuesday",      2, 0, TM_WDAY},
  177. X    {"wednesday",    3, 0, TM_WDAY},
  178. X    {"thursday",     4, 0, TM_WDAY},
  179. X    {"friday",       5, 0, TM_WDAY},
  180. X    {"saturday",     6, 0, TM_WDAY},
  181. X
  182. X    {"gmt",          0*60, TWTIME, TM_ZON},   /* Greenwich */
  183. X    {"gst",          0*60, TWTIME, TM_ZON},
  184. X    {"gdt",          0*60, TWTIME+TWDST, TM_ZON},     /* ?? */
  185. X
  186. X    {"ast",          4*60, TWTIME, TM_ZON},   /* Atlantic */
  187. X    {"est",          5*60, TWTIME, TM_ZON},   /* Eastern */
  188. X    {"cst",          6*60, TWTIME, TM_ZON},   /* Central */
  189. X    {"mst",          7*60, TWTIME, TM_ZON},   /* Mountain */
  190. X    {"pst",          8*60, TWTIME, TM_ZON},   /* Pacific */
  191. X    {"yst",          9*60, TWTIME, TM_ZON},   /* Yukon */
  192. X    {"hst",          10*60, TWTIME, TM_ZON},  /* Hawaii */
  193. X    {"bst",          11*60, TWTIME, TM_ZON},  /* Bering */
  194. X
  195. X    {"adt",          4*60, TWTIME+TWDST, TM_ZON},     /* Atlantic */
  196. X    {"edt",          5*60, TWTIME+TWDST, TM_ZON},     /* Eastern */
  197. X    {"cdt",          6*60, TWTIME+TWDST, TM_ZON},     /* Central */
  198. X    {"mdt",          7*60, TWTIME+TWDST, TM_ZON},     /* Mountain */
  199. X    {"pdt",          8*60, TWTIME+TWDST, TM_ZON},     /* Pacific */
  200. X    {"ydt",          9*60, TWTIME+TWDST, TM_ZON},     /* Yukon */
  201. X    {"hdt",          10*60, TWTIME+TWDST, TM_ZON},    /* Hawaii */
  202. X    {"bdt",          11*60, TWTIME+TWDST, TM_ZON},    /* Bering */
  203. X
  204. X    {"daylight",     1, TWTIME+TWDST, TM_ZON},        /* Local Daylight */
  205. X    {"standard",     1, TWTIME, TM_ZON},      /* Local Standard */
  206. X    {"std",          1, TWTIME, TM_ZON},      /*   "       "    */
  207. X
  208. X    {"am",           1, TWTIME, TM_AMPM},
  209. X    {"pm",           2, TWTIME, TM_AMPM},
  210. X    {"noon",         12,TWTIME+TW1200, 0},    /* Special frobs */
  211. X    {"midnight",     0, TWTIME+TW1200, 0},
  212. X    {"at",           (long)ptnoise, TWSPEC, 0},    /* Noise word */
  213. X
  214. X    {0, 0, 0, 0},             /* Zero entry to terminate searches */
  215. X};
  216. X
  217. X#define TMWILD (-2)    /* Value meaning item specified as wild-card */
  218. X            /* (May use someday...) */
  219. X
  220. Xstruct token {
  221. X    char *tcp;    /* pointer to string */
  222. X    int tcnt;    /* # chars */
  223. X    char tbrk;    /* "break" char */
  224. X    char tbrkl;    /* last break char */
  225. X    char tflg;    /* 0 = alpha, 1 = numeric */
  226. X    union {         /* Resulting value; */
  227. X        int tnum;/* either a #, or */
  228. X        struct tmwent *ttmw;/* ptr to a tmwent. */
  229. X    } tval;
  230. X};
  231. X
  232. Xpartime(astr, atm)
  233. Xchar *astr;
  234. Xstruct tm *atm;
  235. X{    register int *tp;
  236. X    register struct tmwent *twp;
  237. X    register int i;
  238. X    struct token btoken, atoken;
  239. X    char *cp, ch;
  240. X    int ord, midnoon;
  241. X    int (*aproc)();
  242. X
  243. X    tp = (int *)atm;
  244. X    zaptime(tp);             /* Initialize the TM structure */
  245. X    midnoon = TMNULL;        /* and our own temp stuff */
  246. X    btoken.tcnt = btoken.tbrkl = 0;
  247. X    btoken.tcp = astr;
  248. X
  249. Xdomore:
  250. X    if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))    /* Get a token */
  251. X      {     if(btoken.tval.tnum) return(0);         /* Read error? */
  252. X        if(midnoon != TMNULL)            /* EOF, wrap up */
  253. X            return(pt12hack(tp, midnoon));
  254. X        return(1);                /* Win return! */
  255. X      }
  256. X    if(btoken.tflg == 0)        /* Alpha? */
  257. X      {     twp = btoken.tval.ttmw;         /* Yes, get ptr to entry */
  258. X        if(twp->wflgs&TWSPEC)        /* Special alpha crock */
  259. X          {     aproc = (int (*) ()) (twp->wval);
  260. X            if(!(*aproc)(tp, twp, &btoken))
  261. X                return(0);    /* ERR: special word err */
  262. X            goto domore;
  263. X          }
  264. X        if(twp->wflgs&TW1200)
  265. X            if(ptstash(&midnoon,(int)twp->wval))
  266. X                return(0);    /* ERR: noon/midnite clash */
  267. X            else goto domore;
  268. X        if(ptstash(&tp[twp->wtype],(int)twp->wval))
  269. X            return(0);        /* ERR: val already set */
  270. X        if(twp->wtype == TM_ZON)    /* If was zone, hack DST */
  271. X            if(ptstash(&tp[TM_ISDST],(twp->wflgs&TWDST)))
  272. X                return(0);    /* ERR: DST conflict */
  273. X        goto domore;
  274. X      }
  275. X
  276. X    /* Token is number.  Lots of hairy heuristics. */
  277. X    if(btoken.tcnt >= 7)    /* More than 6 digits in string? */
  278. X        return(0);    /* ERR: number too big */
  279. X    if(btoken.tcnt == 6)    /* 6 digits = HHMMSS.  Needs special crock */
  280. X      {            /* since 6 digits are too big for integer! */
  281. X        i = (btoken.tcp[0]-'0')*10    /* Gobble 1st 2 digits */
  282. X           + btoken.tcp[1]-'0';
  283. X        btoken.tcnt = 2;        /* re-read last 4 chars */
  284. X        goto coltime;
  285. X      }
  286. X
  287. X    i = btoken.tval.tnum;   /* Value now known to be valid; get it. */
  288. X    if( btoken.tcnt == 5    /*  5 digits = HMMSS */
  289. X     || btoken.tcnt == 3)    /*  3 digits = HMM   */
  290. X      {    if(btoken.tcnt != 3)
  291. X            if(ptstash(&tp[TM_SEC], i%100))
  292. X                return(0);    /* ERR: sec conflict */
  293. X            else i /= 100;
  294. Xhhmm4:        if(ptstash(&tp[TM_MIN], i%100))
  295. X            return(0);        /* ERR: min conflict */
  296. X        i /= 100;
  297. Xhh2:            if(ptstash(&tp[TM_HOUR], i))
  298. X            return(0);        /* ERR: hour conflict */
  299. X        goto domore;
  300. X      }
  301. X
  302. X    if(btoken.tcnt == 4)    /* 4 digits = YEAR or HHMM */
  303. X      {    if(tp[TM_YEAR] != TMNULL) goto hhmm4;    /* Already got yr? */
  304. X        if(tp[TM_HOUR] != TMNULL) goto year4;    /* Already got hr? */
  305. X        if((i%100) > 59) goto year4;        /* MM >= 60? */
  306. X        if(btoken.tbrk == ':')            /* HHMM:SS ? */
  307. X            if( ptstash(&tp[TM_HOUR],i/100)
  308. X             || ptstash(&tp[TM_MIN], i%100))
  309. X                return(0);        /* ERR: hr/min clash */
  310. X            else goto coltm2;        /* Go handle SS */
  311. X        if(btoken.tbrk != ',' && btoken.tbrk != '/'
  312. X          && ptitoken(btoken.tcp+btoken.tcnt,&atoken)    /* Peek */
  313. X          && atoken.tflg == 0            /* alpha */
  314. X          && (atoken.tval.ttmw->wflgs&TWTIME))  /* HHMM-ZON */
  315. X            goto hhmm4;
  316. X        if(btoken.tbrkl == '-'        /* DD-Mon-YYYY */
  317. X          || btoken.tbrkl == ','    /* Mon DD, YYYY */
  318. X          || btoken.tbrkl == '/'    /* MM/DD/YYYY */
  319. X          || btoken.tbrkl == '.'    /* DD.MM.YYYY */
  320. X          || btoken.tbrk == '-'        /* YYYY-MM-DD */
  321. X            ) goto year4;
  322. X        goto hhmm4;            /* Give up, assume HHMM. */
  323. X      }
  324. X
  325. X    /* From this point on, assume tcnt == 1 or 2 */
  326. X    /* 2 digits = YY, MM, DD, or HH (MM and SS caught at coltime) */
  327. X    if(btoken.tbrk == ':')        /* HH:MM[:SS] */
  328. X        goto coltime;        /*  must be part of time. */
  329. X    if(i > 31) goto yy2;        /* If >= 32, only YY poss. */
  330. X
  331. X    /* Check for numerical-format date */
  332. X    for (cp = "/-."; ch = *cp++;)
  333. X      {    ord = (ch == '.' ? 0 : 1);    /* n/m = D/M or M/D */
  334. X        if(btoken.tbrk == ch)            /* "NN-" */
  335. X          {    if(btoken.tbrkl != ch)
  336. X              {    if(ptitoken(btoken.tcp+btoken.tcnt,&atoken)
  337. X                  && atoken.tflg == 0
  338. X                  && atoken.tval.ttmw->wtype == TM_MON)
  339. X                    goto dd2;
  340. X                if(ord)goto mm2; else goto dd2; /* "NN-" */
  341. X              }                /* "-NN-" */
  342. X            if(tp[TM_DAY] == TMNULL
  343. X            && tp[TM_YEAR] != TMNULL)    /* If "YY-NN-" */
  344. X                goto mm2;        /* then always MM */
  345. X            if(ord)goto dd2; else goto mm2;
  346. X          }
  347. X        if(btoken.tbrkl == ch            /* "-NN" */
  348. X          && tp[ord ? TM_MON : TM_DAY] != TMNULL)
  349. X            if(tp[ord ? TM_DAY : TM_MON] == TMNULL)    /* MM/DD */
  350. X                if(ord)goto dd2; else goto mm2;
  351. X            else goto yy2;            /* "-YY" */
  352. X      }
  353. X
  354. X    /* At this point only YY, DD, and HH are left.
  355. X     * YY is very unlikely since value is <= 32 and there was
  356. X     * no numerical format date.  Make one last try at YY
  357. X     * before dropping through to DD vs HH code.
  358. X     */
  359. X    if(btoken.tcnt == 2        /* If 2 digits */
  360. X      && tp[TM_HOUR] != TMNULL    /* and already have hour */
  361. X      && tp[TM_DAY] != TMNULL    /* and day, but  */
  362. X      && tp[TM_YEAR] == TMNULL)    /* no year, then assume */
  363. X        goto yy2;        /* that's what we have. */
  364. X
  365. X    /* Now reduced to choice between HH and DD */
  366. X    if(tp[TM_HOUR] != TMNULL) goto dd2;    /* Have hour? Assume day. */
  367. X    if(tp[TM_DAY] != TMNULL) goto hh2;    /* Have day? Assume hour. */
  368. X    if(i > 24) goto dd2;            /* Impossible HH means DD */
  369. X    if(!ptitoken(btoken.tcp+btoken.tcnt, &atoken))    /* Read ahead! */
  370. X        if(atoken.tval.tnum) return(0); /* ERR: bad token */
  371. X        else goto dd2;            /* EOF, assume day. */
  372. X    if( atoken.tflg == 0        /* If next token is an alpha */
  373. X     && atoken.tval.ttmw->wflgs&TWTIME)  /* time-spec, assume hour */
  374. X        goto hh2;        /* e.g. "3 PM", "11-EDT"  */
  375. X
  376. Xdd2:    if(ptstash(&tp[TM_DAY],i))    /* Store day (1 based) */
  377. X        return(0);
  378. X    goto domore;
  379. X
  380. Xmm2:    if(ptstash(&tp[TM_MON], i-1))    /* Store month (make zero based) */
  381. X        return(0);
  382. X    goto domore;
  383. X
  384. Xyy2:    i += 1900;
  385. Xyear4:    if(ptstash(&tp[TM_YEAR],i))    /* Store year (full number) */
  386. X        return(0);        /* ERR: year conflict */
  387. X    goto domore;
  388. X
  389. X    /* Hack HH:MM[[:]SS] */
  390. Xcoltime:
  391. X    if(ptstash(&tp[TM_HOUR],i)) return(0);
  392. X    if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
  393. X        return(!btoken.tval.tnum);
  394. X    if(!btoken.tflg) return(0);    /* ERR: HH:<alpha> */
  395. X    if(btoken.tcnt == 4)        /* MMSS */
  396. X        if(ptstash(&tp[TM_MIN],btoken.tval.tnum/100)
  397. X          || ptstash(&tp[TM_SEC],btoken.tval.tnum%100))
  398. X            return(0);
  399. X        else goto domore;
  400. X    if(btoken.tcnt != 2
  401. X      || ptstash(&tp[TM_MIN],btoken.tval.tnum))
  402. X        return(0);        /* ERR: MM bad */
  403. X    if(btoken.tbrk != ':') goto domore;    /* Seconds follow? */
  404. Xcoltm2:    if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
  405. X        return(!btoken.tval.tnum);
  406. X    if(!btoken.tflg || btoken.tcnt != 2    /* Verify SS */
  407. X      || ptstash(&tp[TM_SEC], btoken.tval.tnum))
  408. X        return(0);        /* ERR: SS bad */
  409. X    goto domore;
  410. X}
  411. X
  412. X/* Store date/time value, return 0 if successful.
  413. X * Fails if entry already set to a different value.
  414. X */
  415. Xptstash(adr,val)
  416. Xint *adr;
  417. X{    register int *a;
  418. X    if( *(a=adr) != TMNULL)
  419. X        return(*a != val);
  420. X    *a = val;
  421. X    return(0);
  422. X}
  423. X
  424. X/* This subroutine is invoked for NOON or MIDNIGHT when wrapping up
  425. X * just prior to returning from partime.
  426. X */
  427. Xpt12hack(atp, aval)
  428. Xint *atp, aval;
  429. X{    register int *tp, i, h;
  430. X    tp = atp;
  431. X    if (((i=tp[TM_MIN]) && i != TMNULL)    /* Ensure mins, secs */
  432. X     || ((i=tp[TM_SEC]) && i != TMNULL))    /* are 0 or unspec'd */
  433. X        return(0);            /* ERR: MM:SS not 00:00 */
  434. X    i = aval;            /* Get 0 or 12 (midnite or noon) */
  435. X    if ((h = tp[TM_HOUR]) == TMNULL    /* If hour unspec'd, win */
  436. X     || h == 12)            /* or if 12:00 (matches either) */
  437. X        tp[TM_HOUR] = i;    /* Then set time */
  438. X    else if(!(i == 0        /* Nope, but if midnight and */
  439. X        &&(h == 0 || h == 24)))    /* time matches, can pass. */
  440. X            return(0);    /* ERR: HH conflicts */
  441. X    tp[TM_AMPM] = TMNULL;        /* Always reset this value if won */
  442. X    return(1);
  443. X}
  444. X
  445. X/* Null routine for no-op tokens */
  446. X
  447. Xptnoise() { return(1); }
  448. X
  449. X/* Get a token and identify it to some degree.
  450. X * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
  451. X * hit error of some sort
  452. X */
  453. X
  454. Xptitoken(astr, tkp)
  455. Xregister struct token *tkp;
  456. Xchar *astr;
  457. X{
  458. X    register char *cp;
  459. X    register int i;
  460. X
  461. X    tkp->tval.tnum = 0;
  462. X    if(pttoken(astr,tkp) == 0)
  463. X#ifdef DEBUG
  464. X        {
  465. X        VOID printf("EOF\n");
  466. X        return(0);
  467. X        }
  468. X#else
  469. X        return(0);
  470. X#endif    
  471. X    cp = tkp->tcp;
  472. X
  473. X#ifdef DEBUG
  474. X    i = cp[tkp->tcnt];
  475. X    cp[tkp->tcnt] = 0;
  476. X    VOID printf("Token: \"%s\" ",cp);
  477. X    cp[tkp->tcnt] = i;
  478. X#endif
  479. X
  480. X    if(tkp->tflg)
  481. X        for(i = tkp->tcnt; i > 0; i--)
  482. X            tkp->tval.tnum = (int)tkp->tval.tnum*10 + ((*cp++)-'0');
  483. X    else
  484. X      {     i = ptmatchstr(cp, tkp->tcnt, tmwords);
  485. X        tkp->tval.tnum = i ? i : -1;         /* Set -1 for error */
  486. X
  487. X#ifdef DEBUG
  488. X        if(!i) VOID printf("Not found!\n");
  489. X#endif
  490. X
  491. X        if(!i) return(0);
  492. X      }
  493. X
  494. X#ifdef DEBUG
  495. X    if(tkp->tflg)
  496. X        VOID printf("Val: %d.\n",tkp->tval.tnum);
  497. X    else VOID printf("Found: \"%s\", val: %d., type %d\n",
  498. X        tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
  499. X#endif
  500. X
  501. X    return(1);
  502. X}
  503. X
  504. X/* Read token from input string into token structure */
  505. Xpttoken(astr,tkp)
  506. Xregister struct token *tkp;
  507. Xchar *astr;
  508. X{
  509. X    register char *cp;
  510. X    register int c;
  511. X
  512. X    tkp->tcp = cp = astr;
  513. X    tkp->tbrkl = tkp->tbrk;        /* Set "last break" */
  514. X    tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
  515. X
  516. X    while(c = *cp++)
  517. X      {    switch(c)
  518. X          {    case ' ': case '\t':    /* Flush all whitespace */
  519. X                while((c = *cp++) && isspace(c));
  520. X                cp--;        /* Drop thru to handle brk */
  521. X            case '(': case ')':    /* Perhaps any non-alphanum */
  522. X            case '-': case ',':    /* shd qualify as break? */
  523. X            case '/': case ':': case '.':    /* Break chars */
  524. X                if(tkp->tcnt == 0)    /* If no token yet */
  525. X                  {    tkp->tcp = cp;    /* ignore the brk */
  526. X                    tkp->tbrkl = c;
  527. X                      continue;    /* and go on. */
  528. X                  }
  529. X                tkp->tbrk = c;
  530. X                return(tkp->tcnt);
  531. X          }
  532. X        if(tkp->tcnt == 0)        /* If first char of token, */
  533. X            tkp->tflg = isdigit(c);    /*    determine type */
  534. X          if(( isdigit(c) &&  tkp->tflg)    /* If not first, make sure */
  535. X         ||(!isdigit(c) && !tkp->tflg))    /*    char matches type */
  536. X            tkp->tcnt++;        /* Win, add to token. */
  537. X        else {
  538. X            cp--;            /* Wrong type, back up */
  539. X            tkp->tbrk = c;
  540. X            return(tkp->tcnt);
  541. X          }
  542. X      }
  543. X    return(tkp->tcnt);        /* When hit EOF */
  544. X}
  545. X
  546. X
  547. Xptmatchstr(astr,cnt,astruc)
  548. Xchar *astr;
  549. Xint cnt;
  550. Xstruct tmwent *astruc;
  551. X{    register char *cp, *mp;
  552. X    register int c;
  553. X    struct tmwent *lastptr;
  554. X    struct integ { int word; };   /* For getting at array ptr */
  555. X    int i;
  556. X
  557. X    lastptr = 0;
  558. X    for(;mp = (char *)((struct integ *)astruc)->word; astruc += 1)
  559. X      {    cp = astr;
  560. X        for(i = cnt; i > 0; i--)
  561. X          {    switch((c = *cp++) ^ *mp++)    /* XOR the chars */
  562. X              {    case 0: continue;    /* Exact match */
  563. X                case 040: if(isalpha(c))
  564. X                    continue;
  565. X              }
  566. X            break;
  567. X          }
  568. X        if(i==0)
  569. X            if(*mp == 0) return((unsigned int)astruc);    /* Exact match */
  570. X            else if(lastptr) return(0);    /* Ambiguous */
  571. X            else lastptr = astruc;        /* 1st ambig */
  572. X      }
  573. X    return((unsigned int)lastptr);
  574. X}
  575. X
  576. X
  577. X
  578. Xzaptime(tp)
  579. Xregister int *tp;
  580. X/* clears tm structure pointed to by tp */
  581. X{    register int i;
  582. X    i = (sizeof (struct tm))/(sizeof (int));
  583. X    do *tp++ = TMNULL;        /* Set entry to "unspecified" */
  584. X    while(--i);            /* Faster than FOR */
  585. X}
  586. X@
  587. X
  588. X
  589. X1.4.2.1
  590. Xlog
  591. X@Start of Amiga RCS port branch.
  592. X@
  593. Xtext
  594. X@d31 1
  595. Xa31 5
  596. X<<<<<<< partime.c
  597. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/partime.c,v 1.4.1.1 89/08/11 01:41:57 rsbx Exp Locker: rsbx $";
  598. X=======
  599. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/partime.c,v 1.2 89/09/17 13:34:54 rick Exp $";
  600. X>>>>>>> 1.2
  601. Xa34 11
  602. X<<<<<<< partime.c
  603. X * Revision 1.4.1.1  89/08/11  01:41:57  rsbx
  604. X * Start of cbmvax RCS source branch.
  605. X=======
  606. X * Revision 1.2  89/09/17  13:34:54  rick
  607. X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
  608. X * All changes done with conditional compile (#ifdef AMIGA).  This version
  609. X * compiles correctly with Lattice C version 5.02 or later.
  610. X>>>>>>> 1.2
  611. X * 
  612. X<<<<<<< partime.c
  613. Xa35 3
  614. X * checked in with -k by rsbx at 89.08.10.16.06.05.
  615. X * 
  616. X * Revision 1.4  89/05/01  14:48:46  narten
  617. Xa43 8
  618. X=======
  619. X * Revision 1.3  89/09/16  09:42:36  rick
  620. X * Modified AMIGA changes to work with Lattice C
  621. X * 
  622. X * Revision 1.2  88/09/03  15:08:16  rick
  623. X * Port to AmigaDos.  All done with conditional compiles
  624. X * 
  625. X>>>>>>> 1.2
  626. Xa58 1
  627. X#ifndef AMIGA
  628. Xa61 1
  629. X#endif
  630. Xd76 1
  631. Xa76 1
  632. Xlong ptnoise();
  633. Xd129 1
  634. Xa129 1
  635. X    {"at",           1, 0, 0},    /* Noise word */
  636. Xd152 1
  637. Xa152 2
  638. X{
  639. X    register int *tp;
  640. Xa332 3
  641. X#ifdef AMIGA
  642. Xshort *adr;
  643. X#else
  644. Xd334 1
  645. Xa334 7
  646. X#endif
  647. X{
  648. X#ifdef AMIGA
  649. X    register short *a;
  650. X#else
  651. X    register int *a;
  652. X#endif
  653. Xa344 3
  654. X#ifdef AMIGA
  655. Xshort *atp, aval;
  656. X#else
  657. Xd346 1
  658. Xa346 7
  659. X#endif
  660. X{
  661. X#ifdef AMIGA
  662. X    register short *tp, i, h;
  663. X#else
  664. X    register int *tp, i, h;
  665. X#endif
  666. Xd364 1
  667. Xa364 1
  668. Xlong ptnoise() { return(1); }
  669. Xa379 1
  670. X<<<<<<< partime.c
  671. Xa382 5
  672. X=======
  673. X#ifdef MYDEBUG
  674. X    VOID printf("EOF\n");
  675. X#endif MYDEBUG
  676. X>>>>>>> 1.2
  677. Xd390 1
  678. Xa390 1
  679. X#ifdef MYDEBUG
  680. Xa394 1
  681. X<<<<<<< partime.c
  682. Xa395 3
  683. X=======
  684. X#endif MYDEBUG
  685. X>>>>>>> 1.2
  686. Xd404 1
  687. Xa404 1
  688. X#ifdef MYDEBUG
  689. Xa405 1
  690. X<<<<<<< partime.c
  691. Xa406 3
  692. X=======
  693. X#endif MYDEBUG
  694. X>>>>>>> 1.2
  695. Xd411 1
  696. Xa411 1
  697. X#ifdef MYDEBUG
  698. Xa415 1
  699. X<<<<<<< partime.c
  700. Xa416 3
  701. X=======
  702. X#endif MYDEBUG
  703. X>>>>>>> 1.2
  704. Xa495 3
  705. X#ifdef AMIGA
  706. Xregister short *tp;
  707. X#else
  708. Xa496 1
  709. X#endif
  710. Xa498 3
  711. X#ifdef AMIGA
  712. X    i = (sizeof (struct tm))/(sizeof (short));
  713. X#else
  714. Xa499 1
  715. X#endif
  716. X@
  717. X
  718. X
  719. X1.4.2.2
  720. Xlog
  721. X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
  722. Xsources I have here (and are later than the ones Rick used).
  723. X@
  724. Xtext
  725. X@d31 5
  726. Xa35 1
  727. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/partime.c,v 1.4.2.1 89/10/13 19:17:41 rsbx Exp Locker: rsbx $";
  728. Xd39 1
  729. Xa39 3
  730. X * Revision 1.4.2.1  89/10/13  19:17:41  rsbx
  731. X * Start of Amiga RCS port branch.
  732. X * 
  733. Xd42 6
  734. Xd49 1
  735. Xd62 8
  736. Xd427 2
  737. Xa428 1
  738. X#ifdef MYDEBUG
  739. Xd431 5
  740. Xd448 1
  741. Xd450 3
  742. Xd463 1
  743. Xd465 3
  744. Xd477 1
  745. Xd479 3
  746. Xd520 1
  747. X@
  748. X
  749. X
  750. X1.4.2.3
  751. Xlog
  752. X@Changed $Header$ to $Id$.
  753. X@
  754. Xtext
  755. X@d31 1
  756. Xa31 1
  757. X"$Id$";
  758. Xa34 4
  759. X * Revision 1.4.2.2  89/10/15  15:43:31  rsbx
  760. X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
  761. X * sources I have here (and are later than the ones Rick used).
  762. X * 
  763. X@
  764. X
  765. X
  766. X1.4.1.1
  767. Xlog
  768. X@Start of cbmvax RCS source branch.
  769. X@
  770. Xtext
  771. X@d31 1
  772. Xa31 1
  773. X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/partime.c,v 1.4 89/05/01 14:48:46 narten Exp $";
  774. Xa34 3
  775. X * Revision 1.4  89/05/01  14:48:46  narten
  776. X * checked in with -k by rsbx at 89.08.10.16.06.05.
  777. X * 
  778. X@
  779. SHAR_EOF
  780. echo "extracting rcs/rcs.rcsfiles/rcs.c,v"
  781. sed 's/^X//' << \SHAR_EOF > rcs/rcs.rcsfiles/rcs.c,v
  782. Xhead     4.11;
  783. Xbranch   4.11.2;
  784. Xaccess   ;
  785. Xsymbols  amiga_rcs:4.11.2 cbmvax_source:4.11.1 uunet_june89_dist:4.11;
  786. Xlocks    ; strict;
  787. Xcomment  @ * @;
  788. X
  789. X
  790. X4.11
  791. Xdate     89.05.01.15.12.06;  author narten;  state Exp;
  792. Xbranches 4.11.1.1 4.11.2.1;
  793. Xnext     ;
  794. X
  795. X4.11.1.1
  796. Xdate     89.08.11.01.42.01;  author rsbx;  state Exp;
  797. Xbranches ;
  798. Xnext     ;
  799. X
  800. X4.11.2.1
  801. Xdate     89.10.13.19.17.47;  author rsbx;  state Exp;
  802. Xbranches ;
  803. Xnext     4.11.2.2;
  804. X
  805. X4.11.2.2
  806. Xdate     89.10.15.15.43.36;  author rsbx;  state Exp;
  807. Xbranches ;
  808. Xnext     4.11.2.3;
  809. X
  810. X4.11.2.3
  811. Xdate     89.10.16.19.06.13;  author rsbx;  state Exp;
  812. Xbranches ;
  813. Xnext     4.11.2.4;
  814. X
  815. X4.11.2.4
  816. Xdate     89.10.17.13.17.35;  author rsbx;  state Exp;
  817. Xbranches ;
  818. Xnext     4.11.2.5;
  819. X
  820. X4.11.2.5
  821. Xdate     89.10.30.13.38.35;  author rsbx;  state Exp;
  822. Xbranches ;
  823. Xnext     4.11.2.6;
  824. X
  825. X4.11.2.6
  826. Xdate     89.11.01.14.42.32;  author rsbx;  state Exp;
  827. Xbranches ;
  828. Xnext     4.11.2.7;
  829. X
  830. X4.11.2.7
  831. Xdate     89.11.05.23.14.17;  author rsbx;  state Exp;
  832. Xbranches ;
  833. Xnext     4.11.2.8;
  834. X
  835. X4.11.2.8
  836. Xdate     89.11.12.15.07.03;  author rsbx;  state Exp;
  837. Xbranches ;
  838. Xnext     ;
  839. X
  840. X
  841. Xdesc
  842. X@RCS create/change operation.
  843. X@
  844. X
  845. X
  846. X
  847. X4.11
  848. Xlog
  849. X@checked in with -k by rsbx at 89.08.10.16.06.26.
  850. X@
  851. Xtext
  852. X@/*
  853. X *                      RCS create/change operation
  854. X */
  855. X#ifndef lint
  856. Xstatic char rcsid[]=
  857. X"$Header: /usr/src/local/bin/rcs/src/RCS/rcs.c,v 4.11 89/05/01 15:12:06 narten Exp $ Purdue CS";
  858. X#endif
  859. X/* Copyright (C) 1982, 1988, 1989 Walter Tichy
  860. X * All rights reserved.
  861. X *
  862. X * Redistribution and use in source and binary forms are permitted
  863. X * provided that the above copyright notice and this paragraph are
  864. X * duplicated in all such forms and that any documentation,
  865. X * advertising materials, and other materials related to such
  866. X * distribution and use acknowledge that the software was developed
  867. X * by Walter Tichy.
  868. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  869. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  870. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  871. X *
  872. X * Report all problems and direct all questions to:
  873. X *   rcs-bugs@@cs.purdue.edu
  874. X * 
  875. X
  876. X
  877. X
  878. X
  879. X
  880. X
  881. X
  882. X*/
  883. X
  884. X
  885. X
  886. X
  887. X/* $Log:    rcs.c,v $
  888. X * Revision 4.11  89/05/01  15:12:06  narten
  889. X * changed copyright header to reflect current distribution rules
  890. X * 
  891. X * Revision 4.10  88/11/08  16:01:54  narten
  892. X * didn't install previous patch correctly
  893. X * 
  894. X * Revision 4.9  88/11/08  13:56:01  narten
  895. X * removed include <sysexits.h> (not needed)
  896. X * minor fix for -A option
  897. X * 
  898. X * Revision 4.8  88/11/08  12:01:58  narten
  899. X * changes from  eggert@@sm.unisys.com (Paul Eggert)
  900. X * 
  901. X * Revision 4.8  88/08/09  19:12:27  eggert
  902. X * Don't access freed storage.
  903. X * Use execv(), not system(); yield proper exit status; remove lint.
  904. X * 
  905. X * Revision 4.7  87/12/18  11:37:17  narten
  906. X * lint cleanups (Guy Harris)
  907. X * 
  908. X * Revision 4.6  87/10/18  10:28:48  narten
  909. X * Updating verison numbers. Changes relative to 1.1 are actually 
  910. X * relative to 4.3
  911. X * 
  912. X * Revision 1.4  87/09/24  13:58:52  narten
  913. X * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  914. X * warnings)
  915. X * 
  916. X * Revision 1.3  87/03/27  14:21:55  jenkins
  917. X * Port to suns
  918. X * 
  919. X * Revision 1.2  85/12/17  13:59:09  albitz
  920. X * Changed setstate to rcs_setstate because of conflict with random.o.
  921. X * 
  922. X * Revision 1.1  84/01/23  14:50:09  kcs
  923. X * Initial revision
  924. X * 
  925. X * Revision 4.3  83/12/15  12:27:33  wft
  926. X * rcs -u now breaks most recent lock if it can't find a lock by the caller.
  927. X * 
  928. X * Revision 4.2  83/12/05  10:18:20  wft
  929. X * Added conditional compilation for sending mail.
  930. X * Alternatives: V4_2BSD, V6, USG, and other.
  931. X * 
  932. X * Revision 4.1  83/05/10  16:43:02  wft
  933. X * Simplified breaklock(); added calls to findlock() and getcaller().
  934. X * Added option -b (default branch). Updated -s and -w for -b.
  935. X * Removed calls to stat(); now done by pairfilenames().
  936. X * Replaced most catchints() calls with restoreints().
  937. X * Removed check for exit status of delivermail().
  938. X * Directed all interactive output to stderr.
  939. X * 
  940. X * Revision 3.9.1.1  83/12/02  22:08:51  wft
  941. X * Added conditional compilation for 4.2 sendmail and 4.1 delivermail.
  942. X * 
  943. X * Revision 3.9  83/02/15  15:38:39  wft
  944. X * Added call to fastcopy() to copy remainder of RCS file.
  945. X *
  946. X * Revision 3.8  83/01/18  17:37:51  wft
  947. X * Changed sendmail(): now uses delivermail, and asks whether to break the lock.
  948. X *
  949. X * Revision 3.7  83/01/15  18:04:25  wft
  950. X * Removed putree(); replaced with puttree() in rcssyn.c.
  951. X * Combined putdellog() and scanlogtext(); deleted putdellog().
  952. X * Cleaned up diagnostics and error messages. Fixed problem with
  953. X * mutilated files in case of deletions in 2 files in a single command.
  954. X * Changed marking of selector from 'D' to DELETE.
  955. X *
  956. X * Revision 3.6  83/01/14  15:37:31  wft
  957. X * Added ignoring of interrupts while new RCS file is renamed;
  958. X * Avoids deletion of RCS files by interrupts.
  959. X *
  960. X * Revision 3.5  82/12/10  21:11:39  wft
  961. X * Removed unused variables, fixed checking of return code from diff,
  962. X * introduced variant COMPAT2 for skipping Suffix on -A files.
  963. X *
  964. X * Revision 3.4  82/12/04  13:18:20  wft
  965. X * Replaced getdelta() with gettree(), changed breaklock to update
  966. X * field lockedby, added some diagnostics.
  967. X *
  968. X * Revision 3.3  82/12/03  17:08:04  wft
  969. X * Replaced getlogin() with getpwuid(), flcose() with ffclose(),
  970. X * /usr/ucb/Mail with macro MAIL. Removed handling of Suffix (-x).
  971. X * fixed -u for missing revno. Disambiguated structure members.
  972. X *
  973. X * Revision 3.2  82/10/18  21:05:07  wft
  974. X * rcs -i now generates a file mode given by the umask minus write permission;
  975. X * otherwise, rcs keeps the mode, but removes write permission.
  976. X * I added a check for write error, fixed call to getlogin(), replaced
  977. X * curdir() with getfullRCSname(), cleaned up handling -U/L, and changed
  978. X * conflicting, long identifiers.
  979. X *
  980. X * Revision 3.1  82/10/13  16:11:07  wft
  981. X * fixed type of variables receiving from getc() (char -> int).
  982. X */
  983. X
  984. X
  985. X#include <sys/types.h>
  986. X#include <sys/stat.h>
  987. X#include "rcsbase.h"
  988. X#ifndef lint
  989. Xstatic char rcsbaseid[] = RCSBASE;
  990. X#endif
  991. X
  992. Xextern FILE * fopen();
  993. Xextern char * bindex();
  994. Xextern int  expandsym();                /* get numeric revision name        */
  995. Xextern struct  hshentry  * getnum();
  996. Xextern struct  lock      * addlock();   /* add a lock                       */
  997. Xextern char              * getid();
  998. Xextern char              Klog[], Khead[], Kaccess[], Kbranch[], Ktext[];
  999. X#ifdef COMPAT2
  1000. Xextern char Ksuffix[];
  1001. X#endif
  1002. Xextern char * getcaller();              /* get login of caller              */
  1003. Xextern struct hshentry   * findlock();  /* find and remove lock             */
  1004. Xextern struct hshentry   * genrevs();
  1005. Xextern char * checkid();                /* check an identifier              */
  1006. Xextern char * getfullRCSname();         /* get full path name of RCS file   */
  1007. Xextern char * mktempfile();             /* temporary file name generator    */
  1008. Xextern free();
  1009. Xextern void catchints();
  1010. Xextern void ignoreints();
  1011. Xextern int  nerror;                     /* counter for errors               */
  1012. Xextern int  quietflag;                  /* diagnoses suppressed if true     */
  1013. Xextern char curlogmsg[];                /* current log message              */
  1014. Xextern char * resultfile;               /* filename for fcopy            */
  1015. Xextern FILE *fcopy;                     /* result file during editing       */
  1016. Xextern FILE * finptr;                   /* RCS input file                   */
  1017. Xextern FILE * frewrite;                 /* new RCS file                     */
  1018. Xextern int    rewriteflag;              /* indicates whether input should be*/
  1019. X                    /* echoed to frewrite               */
  1020. X
  1021. Xchar * newRCSfilename, * diffilename, * cutfilename;
  1022. Xchar * RCSfilename, * workfilename;
  1023. Xextern struct stat RCSstat, workstat; /* file status of RCS and work file   */
  1024. Xextern int  haveRCSstat, haveworkstat;/* status indicators                  */
  1025. X
  1026. Xchar accessorlst[strtsize];
  1027. XFILE * fcut;        /* temporary file to rebuild delta tree                 */
  1028. Xint    oldumask;    /* save umask                                           */
  1029. X
  1030. Xint initflag, strictlock, strict_selected, textflag;
  1031. Xchar * textfile, * accessfile;
  1032. Xchar * caller, numrev[30];            /* caller's login;               */
  1033. Xstruct  access  * newaccessor,  * rmvaccessor,  * rplaccessor;
  1034. Xstruct  access  *curaccess,  *rmaccess;
  1035. Xstruct  hshentry        * gendeltas[hshsize];
  1036. X
  1037. Xstruct  Lockrev {
  1038. X        char    * revno;
  1039. X        struct  Lockrev   * nextrev;
  1040. X};
  1041. X
  1042. Xstruct  Symrev {
  1043. X        char    * revno;
  1044. X        char    * ssymbol;
  1045. X        int     override;
  1046. X        struct  Symrev  * nextsym;
  1047. X};
  1048. X
  1049. Xstruct  Status {
  1050. X        char    * revno;
  1051. X        char    * status;
  1052. X        struct  Status  * nextstatus;
  1053. X};
  1054. X
  1055. Xstruct delrevpair {
  1056. X        char    * strt;
  1057. X        char    * end;
  1058. X        int     code;
  1059. X};
  1060. X
  1061. Xstruct  Lockrev * newlocklst,   * rmvlocklst;
  1062. Xstruct  Symrev  * assoclst,  * lastassoc;
  1063. Xstruct  Status  * statelst,  * laststate;
  1064. Xstruct  delrevpair      * delrev;
  1065. Xstruct  hshentry        * cuthead,  *cuttail,  * delstrt;
  1066. Xchar    branchnum[revlength], * branchsym;
  1067. Xstruct  hshentry branchdummy;
  1068. Xchar    * commsyml;
  1069. Xchar    * headstate;
  1070. Xint     lockhead,unlockcaller,chgheadstate,branchflag,commentflag;
  1071. Xint     delaccessflag;
  1072. Xenum    stringwork {copy, edit, empty}; /* expand and edit_expand not needed */
  1073. X
  1074. X
  1075. Xmain (argc, argv)
  1076. Xint argc;
  1077. Xchar * argv[];
  1078. X{
  1079. X        char    *comdusge;
  1080. X        int     result;
  1081. X    struct    access    *removeaccess(),  * getaccessor();
  1082. X        struct  Lockrev *rmnewlocklst();
  1083. X        struct  Lockrev *curlock,  * rmvlock, *lockpt;
  1084. X        struct  Status  * curstate;
  1085. X        struct  access    *temp, *temptr;
  1086. X    int status;
  1087. X
  1088. X    status = 0;
  1089. X        nerror = 0;
  1090. X    catchints();
  1091. X        cmdid = "rcs";
  1092. X        quietflag = false;
  1093. X        comdusge ="command format:\nrcs -i -alogins -Alogins -e[logins] -b[rev] -c[commentleader] -l[rev] -u[rev] -L -U -nname[:rev] -Nname[:rev] -orange -sstate[:rev] -t[textfile] file....";
  1094. X        rplaccessor = nil;     delstrt = nil;
  1095. X        accessfile = textfile = caller = nil;
  1096. X        branchflag = commentflag = chgheadstate = false;
  1097. X        lockhead = false; unlockcaller=false;
  1098. X        initflag= textflag = false;
  1099. X        strict_selected = 0;
  1100. X
  1101. X    caller=getcaller();
  1102. X        laststate = statelst = nil;
  1103. X        lastassoc = assoclst = nil;
  1104. X        curlock = rmvlock = newlocklst = rmvlocklst = nil;
  1105. X        curaccess = rmaccess = rmvaccessor = newaccessor = nil;
  1106. X        delaccessflag = false;
  1107. X
  1108. X        /*  preprocessing command options    */
  1109. X        while (--argc,++argv, argc>=1 && ((*argv)[0] == '-')) {
  1110. X                switch ((*argv)[1]) {
  1111. X
  1112. X                case 'i':   /*  initail version  */
  1113. X                        initflag = true;
  1114. X                        break;
  1115. X
  1116. X                case 'b':  /* change default branch */
  1117. X                        if (branchflag)warn("Redfinition of option -b");
  1118. X                        branchflag= true;
  1119. X                        branchsym = (*argv)+2;
  1120. X                        break;
  1121. X
  1122. X                case 'c':   /*  change comment symbol   */
  1123. X                        if (commentflag)warn("Redefinition of option -c");
  1124. X                        commentflag = true;
  1125. X                        commsyml = (*argv)+2;
  1126. X                        break;
  1127. X
  1128. X                case 'a':  /*  add new accessor   */
  1129. X                        if ( (*argv)[2] == '\0') {
  1130. X                            error("Login name missing after -a");
  1131. X                        }
  1132. X                        if ( (temp = getaccessor((*argv)+1)) ) {
  1133. X                            if ( newaccessor )
  1134. X                                curaccess->nextaccess = temp->nextaccess;
  1135. X                            else
  1136. X                                newaccessor = temp->nextaccess;
  1137. X                            temp->nextaccess = nil;
  1138. X                            curaccess = temp;
  1139. X                        }
  1140. X                        break;
  1141. X
  1142. X                case 'A':  /*  append access list according to accessfile  */
  1143. X                        if ( (*argv)[2] == '\0') {
  1144. X                            error("Missing file name after -A");
  1145. X                            break;
  1146. X                        }
  1147. X                        if ( accessfile) warn("Redefinition of option -A");
  1148. X                        *argv = *argv+2;
  1149. X                        if( pairfilenames(1, argv, true, false) > 0) {
  1150. X                            releaselst(newaccessor);
  1151. X                            newaccessor = curaccess = nil;
  1152. X                            releaselst(rmvaccessor);
  1153. X                            rmvaccessor = rmaccess = nil;
  1154. X                            accessfile = RCSfilename;
  1155. X                        }
  1156. X                        else
  1157. X                            accessfile = nil;
  1158. X                        break;
  1159. X
  1160. X                case 'e':    /*  remove accessors   */
  1161. X                        if ( (*argv)[2] == '\0' ) {
  1162. X                            delaccessflag = true;
  1163. X                            break;
  1164. X                        }
  1165. X                        if ( (temp = getaccessor((*argv)+1))  ) {
  1166. X                            if ( rmvaccessor )
  1167. X                                rmaccess->nextaccess = temp->nextaccess;
  1168. X                            else
  1169. X                                rmvaccessor = temp->nextaccess;
  1170. X                            temptr = temp->nextaccess;
  1171. X                            temp->nextaccess = nil;
  1172. X                            rmaccess = temp;
  1173. X                            while( temptr ) {
  1174. X                                newaccessor = removeaccess(temptr,newaccessor,false);
  1175. X                                temptr = temptr->nextaccess;
  1176. X                            }
  1177. X                            curaccess = temp = newaccessor;
  1178. X                            while( temp){
  1179. X                                curaccess = temp;
  1180. X                                temp = temp->nextaccess;
  1181. X                            }
  1182. X                        }
  1183. X                        break;
  1184. X
  1185. X                case 'l':    /*   lock a revision if it is unlocked   */
  1186. X                        if ( (*argv)[2] == '\0'){ /* lock head or def. branch */
  1187. X                            lockhead = true;
  1188. X                            break;
  1189. X                        }
  1190. X                        lockpt = (struct Lockrev *)talloc(sizeof(struct Lockrev));
  1191. X                        lockpt->revno = (*argv)+2;
  1192. X                        lockpt->nextrev = nil;
  1193. X                        if ( curlock )
  1194. X                            curlock->nextrev = lockpt;
  1195. X                        else
  1196. X                            newlocklst = lockpt;
  1197. X                        curlock = lockpt;
  1198. X                        break;
  1199. X
  1200. X                case 'u':   /*  release lock of a locked revision   */
  1201. X                        if ( (*argv)[2] == '\0'){ /*  unlock head  */
  1202. X                            unlockcaller=true;
  1203. X                            break;
  1204. X                        }
  1205. X                        lockpt = (struct Lockrev *)talloc(sizeof(struct Lockrev));
  1206. X                        lockpt->revno = (*argv)+2;
  1207. X                        lockpt->nextrev = nil;
  1208. X                        if (rmvlock)
  1209. X                            rmvlock->nextrev = lockpt;
  1210. X                        else
  1211. X                            rmvlocklst = lockpt;
  1212. X                        rmvlock = lockpt;
  1213. X
  1214. X                        curlock = rmnewlocklst(lockpt);
  1215. X                        break;
  1216. X
  1217. X                case 'L':   /*  set strict locking */
  1218. X                        if (strict_selected++) {  /* Already selected L or U? */
  1219. X               if (!strictlock)      /* Already selected -U? */
  1220. X                   warn("Option -L overrides -U");
  1221. X                        }
  1222. X                        strictlock = true;
  1223. X                        break;
  1224. X
  1225. X                case 'U':   /*  release strict locking */
  1226. X                        if (strict_selected++) {  /* Already selected L or U? */
  1227. X               if (strictlock)      /* Already selected -L? */
  1228. X                   warn("Option -L overrides -U");
  1229. X                        }
  1230. X            else
  1231. X                strictlock = false;
  1232. X                        break;
  1233. X
  1234. X                case 'n':    /*  add new association: error, if name exists */
  1235. X                        if ( (*argv)[2] == '\0') {
  1236. X                            error("Missing symbolic name after -n");
  1237. X                            break;
  1238. X                        }
  1239. X                        getassoclst(false, (*argv)+1);
  1240. X                        break;
  1241. X
  1242. X                case 'N':   /*  add or change association   */
  1243. X                        if ( (*argv)[2] == '\0') {
  1244. X                            error("Missing symbolic name after -N");
  1245. X                            break;
  1246. X                        }
  1247. X                        getassoclst(true, (*argv)+1);
  1248. X                        break;
  1249. X
  1250. X                case 'o':   /*  delete revisins  */
  1251. X                        if (delrev) warn("Redefinition of option -o");
  1252. X                        if ( (*argv)[2] == '\0' ) {
  1253. X                            error("Missing revision range after -o");
  1254. X                            break;
  1255. X                        }
  1256. X                        getdelrev( (*argv)+1 );
  1257. X                        break;
  1258. X
  1259. X                case 's':   /*  change state attribute of a revision  */
  1260. X                        if ( (*argv)[2] == '\0') {
  1261. X                            error("State missing after -s");
  1262. X                            break;
  1263. X                        }
  1264. X                        getstates( (*argv)+1);
  1265. X                        break;
  1266. X
  1267. X                case 't':   /*  change descriptive text   */
  1268. X                        textflag=true;
  1269. X                        if ((*argv)[2]!='\0'){
  1270. X                                if (textfile!=nil)warn("Redefinition of -t option");
  1271. X                                textfile = (*argv)+2;
  1272. X                        }
  1273. X                        break;
  1274. X
  1275. X                case 'q':
  1276. X                        quietflag = true;
  1277. X                        break;
  1278. X                default:
  1279. X                        faterror("Unknown option: %s\n%s", *argv, comdusge);
  1280. X                };
  1281. X        }  /* end processing of options */
  1282. X
  1283. X        if (argc<1) faterror("No input file\n%s", comdusge);
  1284. X        if (nerror) {   /*  exit, if any error in command options  */
  1285. X            diagnose("%s aborted",cmdid);
  1286. X            exit(1);
  1287. X        }
  1288. X        if (accessfile) /*  get replacement for access list   */
  1289. X            getrplaccess();
  1290. X        if (nerror) {
  1291. X            diagnose("%s aborted",cmdid);
  1292. X            exit(1);
  1293. X        }
  1294. X
  1295. X        /* now handle all filenames */
  1296. X        do {
  1297. X        rewriteflag = false;
  1298. X        finptr=frewrite=NULL;
  1299. X
  1300. X        if ( initflag ) {
  1301. X            switch( pairfilenames(argc, argv, false, false) ) {
  1302. X                case -1: break;        /*  not exist; ok */
  1303. X                case  0: continue;     /*  error         */
  1304. X                case  1: error("file %s exists already", RCSfilename);
  1305. X                         VOID fclose(finptr);
  1306. X                         continue;
  1307. X            }
  1308. X    }
  1309. X        else  {
  1310. X            switch( pairfilenames(argc, argv, true, false) ) {
  1311. X                case -1: continue;    /*  not exist      */
  1312. X                case  0: continue;    /*  errors         */
  1313. X                case  1: break;       /*  file exists; ok*/
  1314. X            }
  1315. X    }
  1316. X
  1317. X
  1318. X        /* now RCSfilename contains the name of the RCS file, and
  1319. X         * workfilename contains the name of the working file.
  1320. X         * if !initflag, finptr contains the file descriptor for the
  1321. X         * RCS file. The admin node is initialized.
  1322. X         */
  1323. X
  1324. X        diagnose("RCS file: %s", RCSfilename);
  1325. X
  1326. X        if (!trydiraccess(RCSfilename))            continue; /* give up */
  1327. X        if (!initflag && !checkaccesslist(caller)) continue; /* give up */
  1328. X        if (!trysema(RCSfilename,true))            continue; /* give up */
  1329. X
  1330. X        gettree(); /* read in delta tree */
  1331. X
  1332. X        /*  update admin. node    */
  1333. X        if (strict_selected) StrictLocks = strictlock;
  1334. X        if (commentflag) Comment = commsyml;
  1335. X
  1336. X        /* update default branch */
  1337. X        if (branchflag && expandsym(branchsym, branchnum)) {
  1338. X            if (countnumflds(branchnum)>0) {
  1339. X                branchdummy.num=branchnum;
  1340. X                Dbranch = &branchdummy;
  1341. X            } else
  1342. X                Dbranch = nil;
  1343. X        }
  1344. X
  1345. X        /*  update access list   */
  1346. X        if ( delaccessflag ) AccessList = nil;
  1347. X        if ( accessfile ) {
  1348. X            temp = rplaccessor;
  1349. X            while( temp ) {
  1350. X                temptr = temp->nextaccess;
  1351. X                if ( addnewaccess(temp) )
  1352. X                    temp->nextaccess = nil;
  1353. X                temp = temptr;
  1354. X            }
  1355. X        }
  1356. X        temp = rmvaccessor;
  1357. X        while(temp)   {         /*  remove accessors from accesslist   */
  1358. X            AccessList = removeaccess(temp, AccessList,true);
  1359. X            temp = temp->nextaccess;
  1360. X        }
  1361. X        temp = newaccessor;
  1362. X        while( temp)  {         /*  add new accessors   */
  1363. X            temptr = temp->nextaccess;
  1364. X            if ( addnewaccess( temp ) )
  1365. X                temp->nextaccess = nil;
  1366. X            temp = temptr;
  1367. X        }
  1368. X
  1369. X        updateassoc();          /*  update association list   */
  1370. X
  1371. X        updatelocks();          /*  update locks              */
  1372. X
  1373. X        /*  update state attribution  */
  1374. X        if (chgheadstate) {
  1375. X            /* change state of default branch or head */
  1376. X            if (Dbranch==nil) {
  1377. X                if (Head==nil)
  1378. X                     warn("Can't change states in an empty tree");
  1379. X                else Head->state = headstate;
  1380. X            } else {
  1381. X                rcs_setstate(Dbranch->num,headstate); /* Can't set directly */
  1382. X            }
  1383. X        }
  1384. X        curstate = statelst;
  1385. X        while( curstate ) {
  1386. X            rcs_setstate(curstate->revno,curstate->status);
  1387. X            curstate = curstate->nextstatus;
  1388. X        }
  1389. X
  1390. X        cuthead = cuttail = nil;
  1391. X        if ( delrev && removerevs()) {
  1392. X            /*  rebuild delta tree if some deltas are deleted   */
  1393. X            if ( cuttail )
  1394. X        VOID genrevs(cuttail->num, (char *)nil,(char *)nil,
  1395. X                 (char *)nil, gendeltas);
  1396. X            buildtree();
  1397. X        }
  1398. X
  1399. X
  1400. X        /* prepare for rewriting the RCS file */
  1401. X        newRCSfilename=mktempfile(RCSfilename,NEWRCSFILE);
  1402. X        oldumask = umask(0222); /* turn off write bits */
  1403. X        if ((frewrite=fopen(newRCSfilename, "w"))==NULL) {
  1404. X                VOID fclose(finptr);
  1405. X                error("Can't open file %s",newRCSfilename);
  1406. X                continue;
  1407. X        }
  1408. X        VOID umask(oldumask);
  1409. X        putadmin(frewrite);
  1410. X        if ( Head )
  1411. X           puttree(Head, frewrite);
  1412. X    putdesc(initflag,textflag,textfile,quietflag);
  1413. X        rewriteflag = false;
  1414. X
  1415. X        if ( Head) {
  1416. X            if (!delrev) {
  1417. X                /* no revision deleted */
  1418. X                fastcopy(finptr,frewrite);
  1419. X            } else {
  1420. X                if ( cuttail )
  1421. X                    buildeltatext(gendeltas);
  1422. X                else
  1423. X                    scanlogtext((struct hshentry *)nil,empty);
  1424. X                    /* copy rest of delta text nodes that are not deleted      */
  1425. X            }
  1426. X        }
  1427. X        ffclose(frewrite);   frewrite = NULL;
  1428. X        if ( ! nerror ) {  /*  move temporary file to RCS file if no error */
  1429. X        ignoreints();        /* ignore interrupts */
  1430. X            if(rename(newRCSfilename,RCSfilename)<0) {
  1431. X                error("Can't create RCS file %s; saved in %s",
  1432. X                   RCSfilename, newRCSfilename);
  1433. X                newRCSfilename[0] = '\0';  /*  avoid deletion by cleanup  */
  1434. X                restoreints();
  1435. X                VOID cleanup();
  1436. X                break;
  1437. X            }
  1438. X            newRCSfilename[0]='\0'; /* avoid re-unlinking by cleanup()*/
  1439. X            /* update mode */
  1440. X            result=0;
  1441. X            if (!initflag) /* preserve mode bits */
  1442. X                result=chmod(RCSfilename,RCSstat.st_mode & ~0222);
  1443. X            elsif (haveworkstat==0)  /* initialization, and work file exists */
  1444. X                result=chmod(RCSfilename,workstat.st_mode & ~0222);
  1445. X            if (result<0) warn("Can't set mode of %s",RCSfilename);
  1446. X
  1447. X            restoreints();                /* catch them all again */
  1448. X            diagnose("done");
  1449. X        } else {
  1450. X        diagnose("%s aborted; %s unchanged.",cmdid,RCSfilename);
  1451. X        status = 1;
  1452. X        nerror = 0;
  1453. X        }
  1454. X        } while (cleanup(),
  1455. X                 ++argv, --argc >=1);
  1456. X
  1457. X        exit(status);
  1458. X}       /* end of main (rcs) */
  1459. X
  1460. X
  1461. X
  1462. Xgetassoclst(flag, sp)
  1463. Xint     flag;
  1464. Xchar    * sp;
  1465. X/*  Function:   associate a symbolic name to a revision or branch,      */
  1466. X/*              and store in assoclst                                   */
  1467. X
  1468. X{
  1469. X        struct   Symrev  * pt;
  1470. X        char             * temp, *temp2;
  1471. X        int                c;
  1472. X
  1473. X        while( (c=(*++sp)) == ' ' || c == '\t' || c =='\n')  ;
  1474. X        temp = sp;
  1475. X        temp2=checkid(sp, ':');  /*  check for invalid symbolic name  */
  1476. X        sp = temp2; c = *sp;   *sp = '\0';
  1477. X        while( c == ' ' || c == '\t' || c == '\n')  c = *++sp;
  1478. X
  1479. X        if ( c != ':' && c != '\0') {
  1480. X        error("Invalid string %s after option -n or -N",sp);
  1481. X            return;
  1482. X        }
  1483. X
  1484. X        pt = (struct Symrev *)talloc(sizeof(struct Symrev));
  1485. X        pt->ssymbol = temp;
  1486. X        pt->override = flag;
  1487. X    if (c == '\0')  /*  delete symbol  */
  1488. X            pt->revno = nil;
  1489. X        else {
  1490. X            while( (c = *++sp) == ' ' || c == '\n' || c == '\t')  ;
  1491. X        if ( c == '\0' )
  1492. X                pt->revno = nil;
  1493. X        else
  1494. X                pt->revno = sp;
  1495. X        }
  1496. X        pt->nextsym = nil;
  1497. X        if (lastassoc)
  1498. X            lastassoc->nextsym = pt;
  1499. X        else
  1500. X            assoclst = pt;
  1501. X        lastassoc = pt;
  1502. X        return;
  1503. X}
  1504. X
  1505. X
  1506. X
  1507. Xstruct access * getaccessor( sp)
  1508. Xchar            *sp;
  1509. X/*   Function:  get the accessor list of options -e and -a,     */
  1510. X/*              and store in curpt                              */
  1511. X
  1512. X
  1513. X{
  1514. X        struct  access  * curpt, * pt,  *pre;
  1515. X        char    *temp;
  1516. X        register c;
  1517. X
  1518. X        while( ( c = *++sp) == ' ' || c == '\n' || c == '\t' || c == ',') ;
  1519. X        if ( c == '\0') {
  1520. X            error("Missing login name after option -a or -e");
  1521. X            return nil;
  1522. X        }
  1523. X
  1524. X        curpt = pt = nil;
  1525. X        while( c != '\0') {
  1526. X                temp=checkid(sp,',');
  1527. X                pt = (struct access *)talloc(sizeof(struct access));
  1528. X                pt->login = sp;
  1529. X                if ( curpt )
  1530. X                    pre->nextaccess = pt;
  1531. X                else
  1532. X                    curpt = pt;
  1533. X                pt->nextaccess = curpt;
  1534. X                pre = pt;
  1535. X                sp = temp;    c = *sp;   *sp = '\0';
  1536. X                while( c == ' ' || c == '\n' || c == '\t'|| c == ',')c =(*++sp);
  1537. X        }
  1538. X        return pt;
  1539. X}
  1540. X
  1541. X
  1542. X
  1543. Xgetstates(sp)
  1544. Xchar    *sp;
  1545. X/*   Function:  get one state attribute and the corresponding   */
  1546. X/*              revision and store in statelst                  */
  1547. X
  1548. X{
  1549. X        char    *temp, *temp2;
  1550. X        struct  Status  *pt;
  1551. X        register        c;
  1552. X
  1553. X        while( (c=(*++sp)) ==' ' || c == '\t' || c == '\n')  ;
  1554. X        temp = sp;
  1555. X        temp2=checkid(sp,':');  /* check for invalid state attribute */
  1556. X        sp = temp2;   c = *sp;   *sp = '\0';
  1557. X        while( c == ' ' || c == '\t' || c == '\n' )  c = *++sp;
  1558. X
  1559. X        if ( c == '\0' ) {  /*  change state of def. branch or Head  */
  1560. X            chgheadstate = true;
  1561. X            headstate  = temp;
  1562. X            return;
  1563. X        }
  1564. X        else if ( c != ':' ) {
  1565. X            error("Missing ':' after state in option -s");
  1566. X            return;
  1567. X        }
  1568. X
  1569. X        while( (c = *++sp) == ' ' || c == '\t' || c == '\n')  ;
  1570. X        pt = (struct Status *)talloc(sizeof(struct Status));
  1571. X        pt->status     = temp;
  1572. X        pt->revno      = sp;
  1573. X        pt->nextstatus = nil;
  1574. X        if (laststate)
  1575. X            laststate->nextstatus = pt;
  1576. X        else
  1577. X            statelst = pt;
  1578. X        laststate = pt;
  1579. X}
  1580. X
  1581. X
  1582. X
  1583. Xgetrplaccess()
  1584. X/*   Function : get the accesslist of the 'accessfile'  */
  1585. X/*              and place in rplaccessor                */
  1586. X{
  1587. X        register        char    *id, *nextp;
  1588. X        struct          access  *newaccess, *oldaccess;
  1589. X
  1590. X        if ( (finptr=fopen(accessfile, "r")) == NULL) {
  1591. X            faterror("Can't open file %s", accessfile);
  1592. X        }
  1593. X        Lexinit();
  1594. X        nextp = &accessorlst[0];
  1595. X
  1596. X        if ( ! getkey(Khead)) faterror("Missing head in %s", accessfile);
  1597. X        VOID getnum();
  1598. X        if ( ! getlex(SEMI) ) serror("Missing ';' after head in %s",accessfile);
  1599. X
  1600. X        if (getkey(Kbranch)) { /* optional */
  1601. X                Dbranch=getnum();
  1602. X                if (!getlex(SEMI)) serror("Missing ';' after branch list");
  1603. X        }
  1604. X
  1605. X
  1606. X#ifdef COMPAT2
  1607. X        /* read suffix. Only in release 2 format */
  1608. X        if (getkey(Ksuffix)) {
  1609. X            if (nexttok==STRING) {
  1610. X                readstring(); nextlex(); /*through away the suffix*/
  1611. X            } elsif(nexttok==ID) {
  1612. X                nextlex();
  1613. X            }
  1614. X            if ( ! getlex(SEMI) ) serror("Missing ';' after suffix in %s",accessfile);
  1615. X        }
  1616. X#endif
  1617. X
  1618. X        if (! getkey(Kaccess))fatserror("Missing access list in %s",accessfile);
  1619. X        oldaccess = nil;
  1620. X        while( id =getid() ) {
  1621. X            newaccess = (struct access *)talloc(sizeof(struct access));
  1622. X            newaccess->login = nextp;
  1623. X            newaccess->nextaccess = nil;
  1624. X            while( ( *nextp++ = *id++) != '\0')  ;
  1625. X            if ( oldaccess )
  1626. X                oldaccess->nextaccess = newaccess;
  1627. X            else
  1628. X                rplaccessor = newaccess;
  1629. X            oldaccess = newaccess;
  1630. X        }
  1631. X        if ( ! getlex(SEMI))serror("Missing ';' after access list in %s",accessfile);
  1632. X        return;
  1633. X}
  1634. X
  1635. X
  1636. X
  1637. Xgetdelrev(sp)
  1638. Xchar    *sp;
  1639. X/*   Function:  get revision range or branch to be deleted,     */
  1640. X/*              and place in delrev                             */
  1641. X{
  1642. X        int    c;
  1643. X        struct  delrevpair      *pt;
  1644. X
  1645. X        if (delrev) free((char *)delrev);
  1646. X
  1647. X        pt = (struct delrevpair *)talloc(sizeof(struct delrevpair));
  1648. X        while((c = (*++sp)) == ' ' || c == '\n' || c == '\t') ;
  1649. X
  1650. X        if ( c == '<' || c == '-' ) {  /*  -o  -rev  or <rev  */
  1651. X            while( (c = (*++sp)) == ' ' || c == '\n' || c == '\t')  ;
  1652. X            pt->strt = sp;    pt->code = 1;
  1653. X            while( c != ' ' && c != '\n' && c != '\t' && c != '\0') c =(*++sp);
  1654. X            *sp = '\0';
  1655. X            pt->end = nil;  delrev = pt;
  1656. X            return;
  1657. X        }
  1658. X        else {
  1659. X            pt->strt = sp;
  1660. X            while( c != ' ' && c != '\n' && c != '\t' && c != '\0'
  1661. X                   && c != '-' && c != '<' )  c = *++sp;
  1662. X            *sp = '\0';
  1663. X            while( c == ' ' || c == '\n' || c == '\t' )  c = *++sp;
  1664. X            if ( c == '\0' )  {  /*   -o rev or branch   */
  1665. X                pt->end = nil;   pt->code = 0;
  1666. X                delrev = pt;
  1667. X                return;
  1668. X            }
  1669. X            if ( c != '-' && c != '<') {
  1670. X                faterror("Invalid range %s %s after -o", pt->strt, sp);
  1671. X                free((char *)pt);
  1672. X                return;
  1673. X            }
  1674. X            while( (c = *++sp) == ' ' || c == '\n' || c == '\t')  ;
  1675. X            if ( c == '\0') {  /*  -o   rev-   or   rev<   */
  1676. X                pt->end = nil;   pt->code = 2;
  1677. X                delrev = pt;
  1678. X                return;
  1679. X            }
  1680. X        }
  1681. X        /*   -o   rev1-rev2    or   rev1<rev2   */
  1682. X        pt->end = sp;  pt->code = 3;   delrev = pt;
  1683. X        while( c!= ' ' && c != '\n' && c != '\t' && c != '\0') c = *++sp;
  1684. X        *sp = '\0';
  1685. X}
  1686. X
  1687. X
  1688. X
  1689. X
  1690. Xscanlogtext(delta,func)
  1691. Xstruct hshentry * delta; enum stringwork func;
  1692. X/* Function: Scans delta text nodes up to and including the one given
  1693. X * by delta, or up to last one present, if delta==nil.
  1694. X * For the one given by delta (if delta!=nil), the log message is saved into
  1695. X * curlogmsg and the text is processed according to parameter func.
  1696. X * Assumes the initial lexeme must be read in first.
  1697. X * Does not advance nexttok after it is finished, except if delta==nil.
  1698. X */
  1699. X{       struct hshentry * nextdelta;
  1700. X
  1701. X        do {
  1702. X                rewriteflag = false;
  1703. X                nextlex();
  1704. X                if (!(nextdelta=getnum())) {
  1705. X                    if(delta)
  1706. X                        faterror("Can't find delta for revision %s", delta->num);
  1707. X                    else return; /* no more delta text nodes */
  1708. X                }
  1709. X                if ( nextdelta->selector != DELETE) {
  1710. X                        rewriteflag = true;
  1711. X                        VOID fprintf(frewrite,DELNUMFORM,nextdelta->num,Klog);
  1712. X                }
  1713. X                if (!getkey(Klog) || nexttok!=STRING)
  1714. X                        serror("Missing log entry");
  1715. X                elsif (delta==nextdelta) {
  1716. X                        VOID savestring(curlogmsg,logsize);
  1717. X                        delta->log=curlogmsg;
  1718. X                } else {readstring();
  1719. X                        if (delta!=nil) delta->log="";
  1720. X                }
  1721. X                nextlex();
  1722. X                if (!getkey(Ktext) || nexttok!=STRING)
  1723. X                        fatserror("Missing delta text");
  1724. X
  1725. X                if(delta==nextdelta)
  1726. X                        /* got the one we're looking for */
  1727. X                        switch (func) {
  1728. X                        case copy:      copystring();
  1729. X                                        break;
  1730. X                        case edit:      editstring((struct hshentry *)nil);
  1731. X                                        break;
  1732. X                        default:        faterror("Wrong scanlogtext");
  1733. X                        }
  1734. X                else    readstring(); /* skip over it */
  1735. X
  1736. X        } while (delta!=nextdelta);
  1737. X}
  1738. X
  1739. X
  1740. X
  1741. Xreleaselst(sourcelst)
  1742. Xstruct  access  * sourcelst;
  1743. X/*   Function:  release the storages whose address are in sourcelst   */
  1744. X
  1745. X{
  1746. X        struct  access  * pt;
  1747. X
  1748. X        pt = sourcelst;
  1749. X        while(pt) {
  1750. X        struct access *pn = pt->nextaccess;
  1751. X            free((char *)pt);
  1752. X            pt = pn;
  1753. X        }
  1754. X}
  1755. X
  1756. X
  1757. X
  1758. Xstruct  Lockrev  * rmnewlocklst(which)
  1759. Xstruct  Lockrev  * which;
  1760. X/*   Function:  remove lock to revision which->revno from newlocklst   */
  1761. X
  1762. X{
  1763. X        struct  Lockrev   * pt, *pre;
  1764. X
  1765. X        while( newlocklst && (! strcmp(newlocklst->revno, which->revno))){
  1766. X        struct Lockrev *pn = newlocklst->nextrev;
  1767. X            free((char *)newlocklst);
  1768. X        newlocklst = pn;
  1769. X        }
  1770. X
  1771. X        pt = pre = newlocklst;
  1772. X        while( pt ) {
  1773. X            if ( ! strcmp(pt->revno, which->revno) ) {
  1774. X                pre->nextrev = pt->nextrev;
  1775. X                free((char *)pt);
  1776. X        pt = pre->nextrev;
  1777. X            }
  1778. X            else {
  1779. X                pre = pt;
  1780. X                pt = pt->nextrev;
  1781. X            }
  1782. X        }
  1783. X        return pre;
  1784. X}
  1785. X
  1786. X
  1787. X
  1788. Xstruct  access  * removeaccess( who, sourcelst,flag)
  1789. Xstruct  access  * who, * sourcelst;
  1790. Xint     flag;
  1791. X/*   Function:  remove the accessor-- who from sourcelst     */
  1792. X
  1793. X{
  1794. X        struct  access  *pt, *pre;
  1795. X
  1796. X        pt = sourcelst;
  1797. X        while( pt && (! strcmp(who->login, pt->login) )) {
  1798. X        pre = pt->nextaccess;
  1799. X            free((char *)pt);
  1800. X        pt = pre;
  1801. X            flag = false;
  1802. X    }
  1803. X        pre = sourcelst = pt;
  1804. X        while( pt ) {
  1805. X            if ( ! strcmp(who->login, pt->login) ) {
  1806. X        pre->nextaccess = pt->nextaccess;
  1807. X        free((char *)pt);
  1808. X        pt = pre->nextaccess;
  1809. X                flag = false;
  1810. X            }
  1811. X            else {
  1812. X                pre = pt;
  1813. X                pt = pt->nextaccess;
  1814. X            }
  1815. X        }
  1816. X        if ( flag ) warn("Can't remove a nonexisting accessor %s",who->login);
  1817. X        return sourcelst;
  1818. X}
  1819. X
  1820. X
  1821. X
  1822. Xint addnewaccess( who )
  1823. Xstruct  access  * who;
  1824. X/*   Function:  add new accessor-- who into AccessList    */
  1825. X
  1826. X{
  1827. X        struct  access  *pt,  *pre;
  1828. X
  1829. X        pre = pt = AccessList;
  1830. X
  1831. X        while( pt ) {
  1832. X            if ( strcmp( who->login, pt->login) ) {
  1833. X                pre = pt;
  1834. X                pt = pt->nextaccess;
  1835. X            }
  1836. X            else
  1837. X                return 0;
  1838. X        }
  1839. X        if ( pre == pt )
  1840. X            AccessList = who;
  1841. X        else
  1842. X            pre->nextaccess = who;
  1843. X        return 1;
  1844. X}
  1845. X
  1846. X
  1847. Xsendmail(Delta, who)
  1848. Xchar    * Delta,  *who;
  1849. X/*   Function:  mail to who, informing him that his lock on delta was
  1850. X *   broken by caller. Ask first whether to go ahead. Return false on
  1851. X *   error or if user decides not to break the lock.
  1852. X */
  1853. X{
  1854. X        char    * messagefile;
  1855. X        int   old1, old2, c, response;
  1856. X        FILE    * mailmess;
  1857. X
  1858. X
  1859. X    VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
  1860. X        VOID fprintf(stderr, "Do you want to break the lock? [ny](n): ");
  1861. X        response=c=getchar();
  1862. X        while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/
  1863. X        if (response=='\n'||response=='n'||response=='N') return false;
  1864. X
  1865. X        /* go ahead with breaking  */
  1866. X        messagefile=mktempfile("/tmp/", "RCSmailXXXXXX");
  1867. X        if ( (mailmess = fopen(messagefile, "w")) == NULL) {
  1868. X            faterror("Can't open file %s", messagefile);
  1869. X        }
  1870. X
  1871. X    VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/'));
  1872. X        VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname());
  1873. X        VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller);
  1874. X        VOID fputs("State the reason for breaking the lock:\n", stderr);
  1875. X        VOID fputs("(terminate with ^D or single '.')\n>> ", stderr);
  1876. X
  1877. X        old1 = '\n';    old2 = ' ';
  1878. X        for (; ;) {
  1879. X            c = getchar();
  1880. X            if ( c == EOF ) {
  1881. X                VOID putc('\n',stderr);
  1882. X                VOID fprintf(mailmess, "%c\n", old1);
  1883. X                break;
  1884. X            }
  1885. X            else if ( c == '\n' && old1 == '.' && old2 == '\n')
  1886. X                break;
  1887. X            else {
  1888. X                VOID fputc( old1, mailmess);
  1889. X                old2 = old1;   old1 = c;
  1890. X                if (c== '\n') VOID fputs(">> ", stderr);
  1891. X            }
  1892. X        }
  1893. X        ffclose(mailmess);
  1894. X
  1895. X    /* ignore the exit status, even if delivermail unsuccessful */
  1896. X        VOID run(messagefile,(char*)nil,
  1897. X#ifdef SENDMAIL
  1898. X        "/usr/lib/sendmail",
  1899. X#else
  1900. X#  ifdef DELIVERMAIL
  1901. X        "/etc/delivermail","-w",
  1902. X#  else
  1903. X        "/bin/mail",
  1904. X#  endif
  1905. X#endif
  1906. X        who,(char*)nil);
  1907. X        VOID unlink(messagefile);
  1908. X    return(true);
  1909. X}
  1910. X
  1911. X
  1912. X
  1913. Xstatic breaklock(who,delta)
  1914. Xchar * who; struct hshentry * delta;
  1915. X/* function: Finds the lock held by who on delta,
  1916. X * and removes it.
  1917. X * Sends mail if a lock different from the caller's is broken.
  1918. X * Prints an error message if there is no such lock or error.
  1919. X */
  1920. X{
  1921. X        register struct lock * next, * trail;
  1922. X        char * num;
  1923. X        struct lock dummy;
  1924. X        int whor, numr;
  1925. X
  1926. X    num=delta->num;
  1927. X        dummy.nextlock=next=Locks;
  1928. X        trail = &dummy;
  1929. X        while (next!=nil) {
  1930. X        if (num != nil)
  1931. X            numr = strcmp(num, next->delta->num);
  1932. X
  1933. X        whor=strcmp(who,next->login);
  1934. X        if (whor==0 && numr==0) break; /* exact match */
  1935. X        if (numr==0 && whor !=0) {
  1936. X                        if (!sendmail( num, next->login)){
  1937. X                            diagnose("%s still locked by %s",num,next->login);
  1938. X                return;
  1939. X                        } else break; /* continue after loop */
  1940. X                }
  1941. X                trail=next;
  1942. X                next=next->nextlock;
  1943. X        }
  1944. X        if (next!=nil) {
  1945. X                /*found one */
  1946. X                diagnose("%s unlocked",next->delta->num);
  1947. X                trail->nextlock=next->nextlock;
  1948. X                next->delta->lockedby=nil;
  1949. X                Locks=dummy.nextlock;
  1950. X        } else  {
  1951. X        error("no lock set on revision %s", num);
  1952. X        }
  1953. X}
  1954. X
  1955. X
  1956. X
  1957. Xstruct hshentry *searchcutpt(object, length, store)
  1958. Xchar    * object;
  1959. Xint     length;
  1960. Xstruct  hshentry   * * store;
  1961. X/*   Function:  Search store and return entry with number being object. */
  1962. X/*              cuttail = nil, if the entry is Head; otherwise, cuttail */
  1963. X/*              is the entry point to the one with number being object  */
  1964. X
  1965. X{
  1966. X        while( compartial( (*store++)->num, object, length)  )  ;
  1967. X        store--;
  1968. X
  1969. X        if ( *store == Head)
  1970. X            cuthead = nil;
  1971. X        else
  1972. X            cuthead = *(store -1);
  1973. X        return *store;
  1974. X}
  1975. X
  1976. X
  1977. X
  1978. Xint  branchpoint(strt, tail)
  1979. Xstruct  hshentry        *strt,  *tail;
  1980. X/*   Function: check whether the deltas between strt and tail    */
  1981. X/*        are locked or branch point, return 1 if any is  */
  1982. X/*        locked or branch point; otherwise, return 0 and */
  1983. X/*              mark DELETE on selector                         */
  1984. X
  1985. X{
  1986. X        struct  hshentry    *pt;
  1987. X    struct lock  *lockpt;
  1988. X        int     flag;
  1989. X
  1990. X
  1991. X        pt = strt;
  1992. X        flag = false;
  1993. X        while( pt != tail) {
  1994. X            if ( pt->branches ){ /*  a branch point  */
  1995. X                flag = true;
  1996. X                error("Can't remove branch point %s", pt->num);
  1997. X            }
  1998. X        lockpt = Locks;
  1999. X        while(lockpt && lockpt->delta != pt)
  2000. X        lockpt = lockpt->nextlock;
  2001. X        if ( lockpt ) {
  2002. X        flag = true;
  2003. X        error("Can't remove locked revision %s",pt->num);
  2004. X        }
  2005. X            pt = pt->next;
  2006. X        }
  2007. X
  2008. X        if ( ! flag ) {
  2009. X            pt = strt;
  2010. X            while( pt != tail ) {
  2011. X                pt->selector = DELETE;
  2012. X                diagnose("deleting revision %s ",pt->num);
  2013. X                pt = pt->next;
  2014. X            }
  2015. X        }
  2016. X        return flag;
  2017. X}
  2018. X
  2019. X
  2020. X
  2021. Xremoverevs()
  2022. X/*   Function:  get the revision range to be removed, and place the     */
  2023. X/*              first revision removed in delstrt, the revision before  */
  2024. X/*              delstrt in cuthead( nil, if delstrt is head), and the   */
  2025. X/*              revision after the last removed revision in cuttail(nil */
  2026. X/*              if the last is a leaf                                   */
  2027. X
  2028. X{
  2029. X        struct  hshentry    *target, *target2, * temp, *searchcutpt();
  2030. X        int     length, flag;
  2031. X
  2032. X        flag = false;
  2033. X        if ( ! expandsym(delrev->strt, &numrev[0]) ) return 0;
  2034. X        target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
  2035. X        if ( ! target ) return 0;
  2036. X        if ( cmpnum(target->num, &numrev[0]) ) flag = true;
  2037. X        length = countnumflds( &numrev[0] );
  2038. X
  2039. X        if ( delrev->code == 0 ) {  /*  -o  rev    or    -o  branch   */
  2040. X        if ( length % 2)
  2041. X        temp=searchcutpt(target->num,length+1,gendeltas);
  2042. X        else if (flag) {
  2043. X                error("Revision %s does not exist", &numrev[0]);
  2044. X        return 0;
  2045. X        }
  2046. X        else
  2047. X        temp = searchcutpt(&numrev[0],length,gendeltas);
  2048. X        cuttail = target->next;
  2049. X            if ( branchpoint(temp, cuttail) ) {
  2050. X                cuttail = nil;
  2051. X                return 0;
  2052. X            }
  2053. X            delstrt = temp;     /* first revision to be removed   */
  2054. X            return 1;
  2055. X        }
  2056. X
  2057. X        if ( length % 2 ) {   /*  invalid branch after -o   */
  2058. X            error("Invalid branch range %s after -o", &numrev[0]);
  2059. X            return 0;
  2060. X        }
  2061. X
  2062. X        if ( delrev->code == 1 )  {  /*  -o  -rev   */
  2063. X            if ( length > 2 ) {
  2064. X                temp = searchcutpt( target->num, length-1, gendeltas);
  2065. X                cuttail = target->next;
  2066. X            }
  2067. X            else {
  2068. X                temp = searchcutpt(target->num, length, gendeltas);
  2069. X                cuttail = target;
  2070. X                while( cuttail && ! cmpnumfld(target->num,cuttail->num,1) )
  2071. X                    cuttail = cuttail->next;
  2072. X            }
  2073. X            if ( branchpoint(temp, cuttail) ){
  2074. X                cuttail = nil;
  2075. X                return 0;
  2076. X            }
  2077. X            delstrt = temp;
  2078. X            return 1;
  2079. X        }
  2080. X
  2081. X        if ( delrev->code == 2 )  {   /*  -o  rev-   */
  2082. X            if ( length == 2 ) {
  2083. X                temp = searchcutpt(target->num, 1,gendeltas);
  2084. X                if ( flag)
  2085. X                    cuttail = target;
  2086. X                else
  2087. X                    cuttail = target->next;
  2088. X            }
  2089. X            else  {
  2090. X                if ( flag){
  2091. X                    cuthead = target;
  2092. X                    if ( !(temp = target->next) ) return 0;
  2093. X                }
  2094. X                else
  2095. X                    temp = searchcutpt(target->num, length, gendeltas);
  2096. X                getbranchno(temp->num, &numrev[0]);  /*  get branch number  */
  2097. X                target = genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
  2098. X            }
  2099. X            if ( branchpoint( temp, cuttail ) ) {
  2100. X                cuttail = nil;
  2101. X                return 0;
  2102. X            }
  2103. X            delstrt = temp;
  2104. X            return 1;
  2105. X        }
  2106. X
  2107. X        /*   -o   rev1-rev2   */
  2108. X        if ( ! expandsym(delrev->end, &numrev[0])  )  return 0;
  2109. X        if ( length != countnumflds( &numrev[0] ) ) {
  2110. X            error("Invalid revision range %s-%s", target->num, &numrev[0]);
  2111. X            return 0;
  2112. X        }
  2113. X        if ( length > 2 && compartial( &numrev[0], target->num, length-1) ) {
  2114. X            error("Invalid revision range %s-%s", target->num, &numrev[0]);
  2115. X            return 0;
  2116. X        }
  2117. X
  2118. X        target2 = genrevs( &numrev[0], (char *)nil, (char *)nil, (char *)nil,gendeltas);
  2119. X        if ( ! target2 ) return 0;
  2120. X
  2121. X        if ( length > 2) {  /* delete revisions on branches  */
  2122. X            if ( cmpnum(target->num, target2->num) > 0) {
  2123. X                if ( cmpnum(target2->num, &numrev[0]) )
  2124. X                    flag = true;
  2125. X                else
  2126. X                    flag = false;
  2127. X                temp = target;
  2128. X                target = target2;
  2129. X                target2 = temp;
  2130. X            }
  2131. X            if ( flag ) {
  2132. X                if ( ! cmpnum(target->num, target2->num) ) {
  2133. X                    error("Revisions %s-%s don't exist", delrev->strt,delrev->end);
  2134. X                    return 0;
  2135. X                }
  2136. X                cuthead = target;
  2137. X                temp = target->next;
  2138. X            }
  2139. X            else
  2140. X                temp = searchcutpt(target->num, length, gendeltas);
  2141. X            cuttail = target2->next;
  2142. X        }
  2143. X        else { /*  delete revisions on trunk  */
  2144. X            if ( cmpnum( target->num, target2->num) < 0 ) {
  2145. X                temp = target;
  2146. X                target = target2;
  2147. X                target2 = temp;
  2148. X            }
  2149. X            else
  2150. X                if ( cmpnum(target2->num, &numrev[0]) )
  2151. X                    flag = true;
  2152. X                else
  2153. X                    flag = false;
  2154. X            if ( flag ) {
  2155. X                if ( ! cmpnum(target->num, target2->num) ) {
  2156. X                    error("Revisions %s-%s don't exist", delrev->strt, delrev->end);
  2157. X                    return 0;
  2158. X                }
  2159. X                cuttail = target2;
  2160. X            }
  2161. X            else
  2162. X                cuttail = target2->next;
  2163. X            temp = searchcutpt(target->num, length, gendeltas);
  2164. X        }
  2165. X        if ( branchpoint(temp, cuttail) )  {
  2166. X            cuttail = nil;
  2167. X            return 0;
  2168. X        }
  2169. X        delstrt = temp;
  2170. X        return 1;
  2171. X}
  2172. X
  2173. X
  2174. X
  2175. Xupdateassoc()
  2176. X/*   Function: add or delete(if revno is nil) association    */
  2177. X/*        which is stored in assoclst            */
  2178. X
  2179. X{
  2180. X        struct  Symrev  * curassoc;
  2181. X    struct  assoc   * pre,  * pt;
  2182. X        struct  hshentry    * target;
  2183. X
  2184. X        /*  add new associations   */
  2185. X        curassoc = assoclst;
  2186. X        while( curassoc ) {
  2187. X            if ( curassoc->revno == nil ) {  /* delete symbol  */
  2188. X        pre = pt = Symbols;
  2189. X                while( pt && strcmp(pt->symbol,curassoc->ssymbol) ) {
  2190. X            pre = pt;
  2191. X            pt = pt->nextassoc;
  2192. X        }
  2193. X        if ( pt )
  2194. X            if ( pre == pt )
  2195. X            Symbols = pt->nextassoc;
  2196. X            else
  2197. X            pre->nextassoc = pt->nextassoc;
  2198. X        else
  2199. X                    warn("Can't delete nonexisting symbol %s",curassoc->ssymbol);
  2200. X        }
  2201. X            else if ( expandsym( curassoc->revno, &numrev[0] ) ) {
  2202. X        /*   add symbol  */
  2203. X               target = (struct hshentry *) talloc(sizeof(struct hshentry));
  2204. X               target->num = &numrev[0];
  2205. X               VOID addsymbol(target, curassoc->ssymbol, curassoc->override);
  2206. X            }
  2207. X            curassoc = curassoc->nextsym;
  2208. X        }
  2209. X
  2210. X}
  2211. X
  2212. X
  2213. X
  2214. Xupdatelocks()
  2215. X/* Function: remove lock for caller or first lock if unlockcaller==true;
  2216. X *           remove locks which are stored in rmvlocklst,
  2217. X *           add new locks which are stored in newlocklst,
  2218. X *           add lock for Dbranch or Head if lockhead==true.
  2219. X */
  2220. X{
  2221. X        struct  hshentry        *target;
  2222. X        struct  Lockrev         *lockpt;
  2223. X
  2224. X        if(unlockcaller == true) { /*  find lock for caller  */
  2225. X            if ( Head ) {
  2226. X        if (Locks) {
  2227. X            target=findlock(caller,true);
  2228. X            if (target==nil) {
  2229. X            breaklock(caller, Locks->delta); /* remove most recent lock */
  2230. X            } else {
  2231. X            diagnose("%s unlocked",target->num);
  2232. X            }
  2233. X        } else {
  2234. X            warn("There are no locks set.");
  2235. X        }
  2236. X            } else {
  2237. X                warn("Can't unlock an empty tree");
  2238. X            }
  2239. X        }
  2240. X
  2241. X        /*  remove locks which are stored in rmvlocklst   */
  2242. X        lockpt = rmvlocklst;
  2243. X        while( lockpt ) {
  2244. X        if (expandsym(lockpt->revno, numrev)) {
  2245. X        target = genrevs(numrev, (char *)nil, (char *)nil, (char *)nil, gendeltas);
  2246. X                if ( target )
  2247. X           if ( !(countnumflds(numrev)%2) && cmpnum(target->num,numrev))
  2248. X            error("Can't unlock nonexisting revision %s",lockpt->revno);
  2249. X                   else
  2250. X                        breaklock(caller, target);
  2251. X                        /* breaklock does its own diagnose */
  2252. X            }
  2253. X            lockpt = lockpt->nextrev;
  2254. X        }
  2255. X
  2256. X        /*  add new locks which stored in newlocklst  */
  2257. X        lockpt = newlocklst;
  2258. X        while( lockpt ) {
  2259. X            setlock(lockpt->revno,caller);
  2260. X            lockpt = lockpt->nextrev;
  2261. X        }
  2262. X
  2263. X        if ( lockhead == true) {  /*  lock default branch or head  */
  2264. X            if (Dbranch) {
  2265. X                setlock(Dbranch->num,caller);
  2266. X            } elsif ( Head) {
  2267. X                if (addlock(Head, caller))
  2268. X                    diagnose("%s locked",Head->num);
  2269. X            } else {
  2270. X                warn("Can't lock an empty tree");
  2271. X            }
  2272. X        }
  2273. X
  2274. X}
  2275. X
  2276. X
  2277. X
  2278. Xsetlock(rev,who)
  2279. Xchar * rev, * who;
  2280. X/* Function: Given a revision or branch number, finds the correponding
  2281. X * delta and locks it for who.
  2282. X */
  2283. X{
  2284. X        struct  lock     *lpt;
  2285. X        struct  hshentry *target;
  2286. X
  2287. X        if (expandsym(rev, &numrev[0]) ){
  2288. X            target = genrevs(&numrev[0],(char *) nil,(char *) nil,
  2289. X                 (char *)nil, gendeltas);
  2290. X            if ( target )
  2291. X               if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num,&numrev[0]))
  2292. X                    error("Can't lock nonexisting revision %s",numrev);
  2293. X               else
  2294. X                    if(lpt=addlock(target, who))
  2295. X                        diagnose("%s locked",lpt->delta->num);
  2296. X        }
  2297. X}
  2298. X
  2299. X
  2300. X
  2301. Xrcs_setstate(rev,status)
  2302. Xchar * rev, * status;
  2303. X/* Function: Given a revision or branch number, finds the corresponding delta
  2304. X * and sets its state to status.
  2305. X */
  2306. X{
  2307. X        struct  hshentry *target;
  2308. X
  2309. X        if ( expandsym(rev, &numrev[0]) ) {
  2310. X            target = genrevs(&numrev[0],(char *) nil, (char *)nil,
  2311. X                 (char *) nil, gendeltas);
  2312. X            if ( target )
  2313. X               if ( !(countnumflds(&numrev[0])%2) && cmpnum(target->num, &numrev[0]) )
  2314. X                    error("Can't set state of nonexisting revision %s to %s",
  2315. X                           numrev,status);
  2316. X               else
  2317. X                    target->state = status;
  2318. X        }
  2319. X}
  2320. X
  2321. X
  2322. X
  2323. X
  2324. X
  2325. Xbuildeltatext(deltas)
  2326. Xstruct  hshentry        ** deltas;
  2327. X/*   Function:  put the delta text on frewrite and make necessary   */
  2328. X/*              change to delta text                                */
  2329. X{
  2330. X        int  i, c, exit_stats;
  2331. X
  2332. X        cuttail->selector = DELETE;
  2333. X        initeditfiles("/tmp/");
  2334. X        scanlogtext(deltas[0], copy);
  2335. X        i = 1;
  2336. X        if ( cuthead )  {
  2337. X            cutfilename=mktempfile("/tmp/", "RCScutXXXXXX");
  2338. X            if ( (fcut = fopen(cutfilename, "w")) == NULL) {
  2339. X                faterror("Can't open temporary file %s", cutfilename);
  2340. X            }
  2341. X
  2342. X            while( deltas[i-1] != cuthead )  {
  2343. X                scanlogtext(deltas[i++], edit);
  2344. X            }
  2345. X
  2346. X            finishedit((struct hshentry *)nil);    rewind(fcopy);
  2347. X            while( (c = getc(fcopy)) != EOF) VOID putc(c, fcut);
  2348. X            swapeditfiles(false);
  2349. X            ffclose(fcut);
  2350. X        }
  2351. X
  2352. X        while( deltas[i-1] != cuttail)
  2353. X            scanlogtext(deltas[i++], edit);
  2354. X        finishedit((struct hshentry *)nil);    ffclose(fcopy);
  2355. X
  2356. X        if ( cuthead ) {
  2357. X            diffilename=mktempfile("/tmp/", "RCSdifXXXXXX");
  2358. X            exit_stats = run((char*)nil,diffilename,
  2359. X            DIFF,"-n",cutfilename,resultfile,(char*)nil);
  2360. X            if (exit_stats != 0 && exit_stats != (1 << BYTESIZ))
  2361. X                faterror ("diff failed");
  2362. X            if(!putdtext(cuttail->num,curlogmsg,diffilename,frewrite)) return;
  2363. X        }
  2364. X        else
  2365. X            if (!putdtext(cuttail->num,curlogmsg,resultfile,frewrite)) return;
  2366. X
  2367. X        scanlogtext((struct hshentry *)nil,empty); /* read the rest of the deltas */
  2368. X}
  2369. X
  2370. X
  2371. X
  2372. Xbuildtree()
  2373. X/*   Function:  actually removes revisions whose selector field  */
  2374. X/*              is DELETE, and rebuilds  the linkage of deltas.  */
  2375. X/*              asks for reconfirmation if deleting last revision*/
  2376. X{
  2377. X    int c,  response;
  2378. X
  2379. X    struct    hshentry   * Delta;
  2380. X        struct  branchhead      *pt, *pre;
  2381. X
  2382. X        if ( cuthead )
  2383. X           if ( cuthead->next == delstrt )
  2384. X                cuthead->next = cuttail;
  2385. X           else {
  2386. X                pre = pt = cuthead->branches;
  2387. X                while( pt && pt->hsh != delstrt )  {
  2388. X                    pre = pt;
  2389. X                    pt = pt->nextbranch;
  2390. X                }
  2391. X                if ( cuttail )
  2392. X                    pt->hsh = cuttail;
  2393. X                else if ( pt == pre )
  2394. X                    cuthead->branches = pt->nextbranch;
  2395. X                else
  2396. X                    pre->nextbranch = pt->nextbranch;
  2397. X            }
  2398. X    else {
  2399. X            if ( cuttail == nil && !quietflag) {
  2400. X                VOID fprintf(stderr,"Do you really want to delete all revisions ?[ny](n): ");
  2401. X        c = response = getchar();
  2402. X        while( c != EOF && c != '\n') c = getchar();
  2403. X                if ( response != 'y' && response != 'Y') {
  2404. X                    diagnose("No revision deleted");
  2405. X            Delta = delstrt;
  2406. X            while( Delta) {
  2407. X            Delta->selector = 'S';
  2408. X            Delta = Delta->next;
  2409. X            }
  2410. X            return;
  2411. X        }
  2412. X        }
  2413. X            Head = cuttail;
  2414. X    }
  2415. X        return;
  2416. X}
  2417. X
  2418. X@
  2419. X
  2420. X
  2421. X4.11.2.1
  2422. Xlog
  2423. X@Start of Amiga RCS port branch.
  2424. X@
  2425. Xtext
  2426. X@d6 1
  2427. Xa6 5
  2428. X<<<<<<< rcs.c
  2429. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS.cbmvax/rcs.c,v 4.11.1.1 89/08/11 01:42:01 rsbx Exp Locker: rsbx $ Purdue CS";
  2430. X=======
  2431. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 1.2 89/09/17 13:35:01 rick Exp $ Purdue CS";
  2432. X>>>>>>> 1.2
  2433. Xa36 11
  2434. X<<<<<<< rcs.c
  2435. X * Revision 4.11.1.1  89/08/11  01:42:01  rsbx
  2436. X * Start of cbmvax RCS source branch.
  2437. X=======
  2438. X * Revision 1.2  89/09/17  13:35:01  rick
  2439. X * Port to AmigaDos done by Rick Schaeffer (ricks@@iscuva.iscs.com)
  2440. X * All changes done with conditional compile (#ifdef AMIGA).  This version
  2441. X * compiles correctly with Lattice C version 5.02 or later.
  2442. X>>>>>>> 1.2
  2443. X * 
  2444. X<<<<<<< rcs.c
  2445. Xa37 3
  2446. X * checked in with -k by rsbx at 89.08.10.16.06.26.
  2447. X * 
  2448. X * Revision 4.11  89/05/01  15:12:06  narten
  2449. Xa53 11
  2450. X=======
  2451. X * Revision 1.4  89/09/16  09:42:43  rick
  2452. X * Modified AMIGA changes to work with Lattice C
  2453. X * 
  2454. X * Revision 1.3  89/09/10  09:26:56  rick
  2455. X * Moved TARGETDIR to rcs:
  2456. X * 
  2457. X * Revision 1.2  88/09/03  15:08:35  rick
  2458. X * Port to AmigaDos.  All done with conditional compiles
  2459. X * 
  2460. X>>>>>>> 1.2
  2461. Xa133 3
  2462. X#ifdef AMIGA
  2463. X#include "stat.h"
  2464. X#else
  2465. Xa135 9
  2466. X<<<<<<< rcs.c
  2467. X=======
  2468. X#endif
  2469. X#ifdef BSD
  2470. X#include <sysexits.h>
  2471. X#else
  2472. X#define EX_OK 0
  2473. X#endif
  2474. X>>>>>>> 1.2
  2475. Xa578 5
  2476. X#ifdef AMIGA
  2477. X        if (finptr != NULL)
  2478. X            fclose(finptr);
  2479. X        unlink(RCSfilename);
  2480. X#endif
  2481. Xa590 3
  2482. X#ifdef AMIGA
  2483. X                result=chmod(RCSfilename,RCSstat.st_attr | S_IWRITE);
  2484. X#else
  2485. Xa591 1
  2486. X#endif
  2487. Xa592 3
  2488. X#ifdef AMIGA
  2489. X                result=chmod(RCSfilename,workstat.st_attr | S_IWRITE);
  2490. X#else
  2491. Xa593 1
  2492. X#endif
  2493. Xd673 1
  2494. Xa673 1
  2495. X        curpt = pt = pre = nil;
  2496. Xd1007 1
  2497. Xa1007 3
  2498. X#ifdef AMIGA
  2499. X    return false;
  2500. X#else
  2501. Xa1057 1
  2502. X#endif AMIGA
  2503. Xa1060 1
  2504. X<<<<<<< rcs.c
  2505. Xa1062 3
  2506. X=======
  2507. Xstruct hshentry * breaklock(who,delta)
  2508. X>>>>>>> 1.2
  2509. Xa1485 3
  2510. X#ifdef AMIGA
  2511. X            cutfilename=mktempfile("t:", "RCScutXXXXXX");
  2512. X#else
  2513. Xa1486 1
  2514. X#endif
  2515. Xa1505 3
  2516. X#ifdef AMIGA
  2517. X            diffilename=mktempfile("t:", "RCSdifXXXXXX");
  2518. X#else
  2519. Xa1506 1
  2520. X<<<<<<< rcs.c
  2521. Xa1508 5
  2522. X=======
  2523. X#endif
  2524. X            VOID sprintf(command, "%s -n %s %s >%s", DIFF,cutfilename, resultfile, diffilename);
  2525. X            exit_stats = system (command);
  2526. X>>>>>>> 1.2
  2527. Xa1549 3
  2528. X#ifdef AMIGA
  2529. X        fflush(stderr);
  2530. X#endif
  2531. X@
  2532. X
  2533. X
  2534. X4.11.2.2
  2535. Xlog
  2536. X@Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
  2537. Xsources I have here (and are later than the ones Rick used).
  2538. X@
  2539. Xtext
  2540. X@d6 5
  2541. Xa10 1
  2542. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.1 89/10/13 19:17:47 rsbx Exp Locker: rsbx $ Purdue CS";
  2543. Xd41 1
  2544. Xa41 3
  2545. X * Revision 4.11.2.1  89/10/13  19:17:47  rsbx
  2546. X * Start of Amiga RCS port branch.
  2547. X * 
  2548. Xd44 6
  2549. Xd51 1
  2550. Xd72 11
  2551. Xd168 2
  2552. Xd176 1
  2553. Xa1049 1
  2554. X#ifdef AMIGA
  2555. Xd1061 2
  2556. Xa1062 40
  2557. X    VOID fprintf(stderr, "Revision %s is already locked by %s.\n", Delta, who);
  2558. X        VOID fprintf(stderr, "Do you want to break the lock? [ny](n): ");
  2559. X        response=c=getchar();
  2560. X        while (!(c==EOF || c=='\n')) c=getchar();/*skip to end of line*/
  2561. X        if (response=='\n'||response=='n'||response=='N') return false;
  2562. X
  2563. X        /* go ahead with breaking  */
  2564. X        messagefile=mktempfile("/tmp/", "RCSmailXXXXXX");
  2565. X        if ( (mailmess = fopen(messagefile, "w")) == NULL) {
  2566. X            faterror("Can't open file %s", messagefile);
  2567. X        }
  2568. X
  2569. X    VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",bindex(RCSfilename,'/'));
  2570. X        VOID fprintf(mailmess, "Your lock on revision %s of file %s\n",Delta, getfullRCSname());
  2571. X        VOID fprintf(mailmess,"has been broken by %s for the following reason:\n",caller);
  2572. X        VOID fputs("State the reason for breaking the lock:\n", stderr);
  2573. X        VOID fputs("(terminate with ^D or single '.')\n>> ", stderr);
  2574. X
  2575. X        old1 = '\n';    old2 = ' ';
  2576. X        for (; ;) {
  2577. X            c = getchar();
  2578. X            if ( c == EOF ) {
  2579. X                VOID putc('\n',stderr);
  2580. X                VOID fprintf(mailmess, "%c\n", old1);
  2581. X                break;
  2582. X            }
  2583. X            else if ( c == '\n' && old1 == '.' && old2 == '\n')
  2584. X                break;
  2585. X            else {
  2586. X                VOID fputc( old1, mailmess);
  2587. X                old2 = old1;   old1 = c;
  2588. X                if (c== '\n') VOID fputs(">> ", stderr);
  2589. X            }
  2590. X        }
  2591. X        ffclose(mailmess);
  2592. X
  2593. X    /* ignore the exit status, even if delivermail unsuccessful */
  2594. X        VOID run(messagefile,(char*)nil,
  2595. X#ifdef SENDMAIL
  2596. X        "/usr/lib/sendmail",
  2597. Xa1063 24
  2598. X#  ifdef DELIVERMAIL
  2599. X        "/etc/delivermail","-w",
  2600. X#  else
  2601. X        "/bin/mail",
  2602. X#  endif
  2603. X#endif
  2604. X        who,(char*)nil);
  2605. X        VOID unlink(messagefile);
  2606. X    return(true);
  2607. X}
  2608. X
  2609. X#else
  2610. X
  2611. Xsendmail(Delta, who)
  2612. Xchar    * Delta,  *who;
  2613. X/*   Function:  mail to who, informing him that his lock on delta was
  2614. X *   broken by caller. Ask first whether to go ahead. Return false on
  2615. X *   error or if user decides not to break the lock.
  2616. X */
  2617. X{
  2618. X        char    * messagefile;
  2619. X        int   old1, old2, c, response;
  2620. X        FILE    * mailmess;
  2621. X
  2622. Xd1114 1
  2623. Xa1115 1
  2624. X#endif AMIGA
  2625. Xd1118 1
  2626. Xd1120 4
  2627. Xa1123 1
  2628. Xstatic void breaklock(who,delta)
  2629. Xd1307 1
  2630. Xa1307 1
  2631. X                genrevs(&numrev[0], (char *)nil, (char *)nil, (char *)nil, gendeltas);
  2632. Xd1575 1
  2633. Xa1575 2
  2634. X#endif
  2635. X/* <<<<<<< rcs.c */
  2636. Xd1578 2
  2637. Xa1579 1
  2638. X/* =======
  2639. Xd1582 1
  2640. Xa1582 1
  2641. X>>>>>>> 1.2 */
  2642. X@
  2643. X
  2644. X
  2645. X4.11.2.3
  2646. Xlog
  2647. X@Changed file path handling to deal with Amiga file path sematics.
  2648. X@
  2649. Xtext
  2650. X@d6 1
  2651. Xa6 1
  2652. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.2 89/10/15 15:43:36 rsbx Exp $ Purdue CS";
  2653. Xa36 4
  2654. X * Revision 4.11.2.2  89/10/15  15:43:36  rsbx
  2655. X * Finished the integration of Rick Schaeffer's RCS Amiga port with the RCS
  2656. X * sources I have here (and are later than the ones Rick used).
  2657. X * 
  2658. Xd160 1
  2659. Xa160 1
  2660. Xextern char * fnamepart();
  2661. Xd1051 1
  2662. Xa1051 1
  2663. X    VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",fnamepart(RCSfilename));
  2664. Xd1116 1
  2665. Xa1116 1
  2666. X    VOID fprintf(mailmess, "Subject: Broken lock on %s\n\n",fnamepart(RCSfilename));
  2667. X@
  2668. X
  2669. X
  2670. X4.11.2.4
  2671. Xlog
  2672. X@Changes to sendmail().
  2673. X@
  2674. Xtext
  2675. X@d6 1
  2676. Xa6 1
  2677. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.3 89/10/16 19:06:13 rsbx Exp $ Purdue CS";
  2678. Xa36 3
  2679. X * Revision 4.11.2.3  89/10/16  19:06:13  rsbx
  2680. X * Changed file path handling to deal with Amiga file path sematics.
  2681. X * 
  2682. Xd1031 11
  2683. Xd1043 54
  2684. Xa1103 4
  2685. X#ifdef AMIGA
  2686. X    VOID fprintf(stderr, "Breaking of locks not supported by this Amiga RCS revision\n");
  2687. X    return false;
  2688. X#else
  2689. Xd1158 1
  2690. Xa1159 1
  2691. X}
  2692. Xd1616 1
  2693. Xd1619 4
  2694. X@
  2695. X
  2696. X
  2697. X4.11.2.5
  2698. Xlog
  2699. X@NULL finptr after closing it.
  2700. X@
  2701. Xtext
  2702. X@d6 1
  2703. Xa6 1
  2704. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.4 89/10/17 13:17:35 rsbx Exp $ Purdue CS";
  2705. Xa36 3
  2706. X * Revision 4.11.2.4  89/10/17  13:17:35  rsbx
  2707. X * Changes to sendmail().
  2708. X * 
  2709. Xd606 1
  2710. Xa606 1
  2711. X            fclose(finptr); finptr = NULL;
  2712. X@
  2713. X
  2714. X
  2715. X4.11.2.6
  2716. Xlog
  2717. X@Changes to make the delete bit to track the write bit. Made protection
  2718. Xbit manipulation less insane.
  2719. X@
  2720. Xtext
  2721. X@d6 1
  2722. Xa6 1
  2723. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.5 89/10/30 13:38:35 rsbx Exp $ Purdue CS";
  2724. Xa36 3
  2725. X * Revision 4.11.2.5  89/10/30  13:38:35  rsbx
  2726. X * NULL finptr after closing it.
  2727. X * 
  2728. Xd608 3
  2729. Xa610 8
  2730. X        if (finptr != NULL) {
  2731. X        fclose(finptr); finptr = NULL;
  2732. X        if (chmod(RCSfilename, RCSstat.st_attr|S_IDELETE)<0)
  2733. X            warn("Can't adjust mode of %s",RCSfilename);
  2734. X        if (unlink(RCSfilename) != 0) {            /* Remove failed   */
  2735. X            error("Can't unlink %s",RCSfilename);
  2736. X            }
  2737. X        }
  2738. Xd625 1
  2739. Xa625 1
  2740. X                result=chmod(RCSfilename,RCSstat.st_attr & ~(S_IWRITE|S_IDELETE));
  2741. Xd631 1
  2742. Xa631 1
  2743. X                result=chmod(RCSfilename,workstat.st_attr & ~(S_IWRITE|S_IDELETE));
  2744. Xd1533 1
  2745. Xa1533 1
  2746. X            cutfilename=mktempfile("t:", "RCScutXXXXXXXX");
  2747. Xd1535 1
  2748. Xa1535 1
  2749. X            cutfilename=mktempfile("/tmp/", "RCScutXXXXXXXX");
  2750. Xd1557 1
  2751. Xa1557 1
  2752. X            diffilename=mktempfile("t:", "RCSdifXXXXXXXX");
  2753. Xd1559 1
  2754. Xa1559 1
  2755. X            diffilename=mktempfile("/tmp/", "RCSdifXXXXXXXX");
  2756. X@
  2757. X
  2758. X
  2759. X4.11.2.7
  2760. Xlog
  2761. X@Fixed a "/tmp/" that slipped through.
  2762. X@
  2763. Xtext
  2764. X@d6 1
  2765. Xa6 1
  2766. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.6 89/11/01 14:42:32 rsbx Exp $ Purdue CS";
  2767. Xa36 4
  2768. X * Revision 4.11.2.6  89/11/01  14:42:32  rsbx
  2769. X * Changes to make the delete bit to track the write bit. Made protection
  2770. X * bit manipulation less insane.
  2771. X * 
  2772. Xa1535 3
  2773. X#ifdef AMIGA
  2774. X        initeditfiles("t:");
  2775. X#else
  2776. Xa1536 1
  2777. X#endif
  2778. X@
  2779. X
  2780. X
  2781. X4.11.2.8
  2782. Xlog
  2783. X@WaitChild() on the Amiga returns the completion code from a child process
  2784. Xwithout shifting it up 8 bits like the Unix wait() does.
  2785. X@
  2786. Xtext
  2787. X@d6 1
  2788. Xa6 1
  2789. X"$Header: /u/softeng/rsbx/rcs/amiga/RCS/rcs.c,v 4.11.2.7 89/11/05 23:14:17 rsbx Exp $ Purdue CS";
  2790. Xa36 3
  2791. X * Revision 4.11.2.7  89/11/05  23:14:17  rsbx
  2792. X * Fixed a "/tmp/" that slipped through.
  2793. X * 
  2794. Xa1578 3
  2795. X#ifdef AMIGA
  2796. X            if (exit_stats != 0 && exit_stats != 1)
  2797. X#else
  2798. Xa1579 1
  2799. X#endif
  2800. X@
  2801. X
  2802. X
  2803. X4.11.1.1
  2804. Xlog
  2805. X@Start of cbmvax RCS source branch.
  2806. X@
  2807. Xtext
  2808. X@d6 1
  2809. Xa6 1
  2810. X"$Header: /u/softeng/rsbx/rcs/rcs.uunet/src/RCS/rcs.c,v 4.11 89/05/01 15:12:06 narten Exp $ Purdue CS";
  2811. Xa36 3
  2812. X * Revision 4.11  89/05/01  15:12:06  narten
  2813. X * checked in with -k by rsbx at 89.08.10.16.06.26.
  2814. X * 
  2815. X@
  2816. SHAR_EOF
  2817. echo "End of archive 7 (of 14)"
  2818. # if you want to concatenate archives, remove anything after this line
  2819. exit
  2820.